aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md20
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/abstract_controller/collector.rb4
-rw-r--r--actionpack/lib/abstract_controller/translation.rb8
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb9
-rw-r--r--actionpack/lib/action_controller/metal/flash.rb33
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb14
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb3
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb10
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb2
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb3
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb31
-rw-r--r--actionpack/lib/action_controller/test_case.rb67
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb18
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb18
-rw-r--r--actionpack/lib/action_dispatch/middleware/head.rb18
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb10
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb121
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb30
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb11
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb8
-rw-r--r--actionpack/lib/action_view/context.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb58
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb4
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb72
-rw-r--r--actionpack/lib/action_view/lookup_context.rb7
-rw-r--r--actionpack/lib/action_view/renderer/abstract_renderer.rb6
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb5
-rw-r--r--actionpack/test/abstract/translation_test.rb13
-rw-r--r--actionpack/test/abstract_unit.rb2
-rw-r--r--actionpack/test/controller/filters_test.rb11
-rw-r--r--actionpack/test/controller/flash_test.rb27
-rw-r--r--actionpack/test/controller/http_token_authentication_test.rb8
-rw-r--r--actionpack/test/controller/mime_responds_test.rb4
-rw-r--r--actionpack/test/controller/new_base/render_action_test.rb8
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb2
-rw-r--r--actionpack/test/controller/new_base/render_text_test.rb2
-rw-r--r--actionpack/test/controller/test_case_test.rb9
-rw-r--r--actionpack/test/dispatch/mapper_test.rb9
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb14
-rw-r--r--actionpack/test/dispatch/request_test.rb8
-rw-r--r--actionpack/test/dispatch/routing/inspector_test.rb170
-rw-r--r--actionpack/test/dispatch/routing_test.rb52
-rw-r--r--actionpack/test/fixtures/project.rb2
-rw-r--r--actionpack/test/fixtures/reply.rb2
-rw-r--r--actionpack/test/fixtures/test/_changing_priority.html.erb1
-rw-r--r--actionpack/test/fixtures/test/_changing_priority.json.erb1
-rw-r--r--actionpack/test/fixtures/test/_first_json_partial.json.erb1
-rw-r--r--actionpack/test/fixtures/test/_json_change_priority.json.erb0
-rw-r--r--actionpack/test/fixtures/test/_second_json_partial.json.erb1
-rw-r--r--actionpack/test/fixtures/test/change_priorty.html.erb2
-rw-r--r--actionpack/test/fixtures/test/html_template.html.erb1
-rw-r--r--actionpack/test/template/active_model_helper_test.rb14
-rw-r--r--actionpack/test/template/capture_helper_test.rb18
-rw-r--r--actionpack/test/template/erb/tag_helper_test.rb3
-rw-r--r--actionpack/test/template/form_options_helper_test.rb28
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb48
-rw-r--r--actionpack/test/template/render_test.rb10
-rw-r--r--actionpack/test/template/test_case_test.rb12
-rw-r--r--actionpack/test/template/url_helper_test.rb99
67 files changed, 976 insertions, 226 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 7edba84ff6..ec85f67e58 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,23 @@
## Rails 4.0.0 (unreleased) ##
+* Remove ActionDispatch::Head middleware in favor of Rack::Head. *Santiago Pastorino*
+
+* Deprecate `:confirm` in favor of `:data => { :confirm => "Text" }` option for `button_to`, `button_tag`, `image_submit_tag`, `link_to` and `submit_tag` helpers.
+
+ *Carlos Galdino + Rafael Mendonça França*
+
+* Show routes in exception page while debugging a `RoutingError` in development. *Richard Schneeman and Mattt Thompson*
+
+* Add `ActionController::Flash.add_flash_types` method to allow people to register their own flash types. e.g.:
+
+ class ApplicationController
+ add_flash_types :error, :warning
+ end
+
+ If you add the above code, you can use `<%= error %>` in an erb, and `redirect_to /foo, :error => 'message'` in a controller.
+
+ *kennyj*
+
* Remove Active Model dependency from Action Pack. *Guillermo Iguaran*
* Support unicode characters in routes. Route will be automatically escaped, so instead of manually escaping:
@@ -79,7 +97,7 @@
* Templates without a handler extension now raises a deprecation warning but still
defaults to ERb. In future releases, it will simply return the template contents. *Steve Klabnik*
-* Remove `:disable_with` in favor of `'data-disable-with'` option from `submit_tag`, `button_tag` and `button_to` helpers.
+* Deprecate `:disable_with` in favor of `:data => { :disable_with => "Text" }` option from `submit_tag`, `button_tag` and `button_to` helpers.
*Carlos Galdino + Rafael Mendonça França*
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 6075e2f02b..dde51da497 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_dependency('builder', '~> 3.0.0')
s.add_dependency('rack', '~> 1.4.1')
s.add_dependency('rack-test', '~> 0.6.1')
- s.add_dependency('journey', '~> 1.0.1')
+ s.add_dependency('journey', '~> 2.0.0')
s.add_dependency('erubis', '~> 2.7.0')
s.add_development_dependency('activemodel', version)
diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb
index 492329c401..09b9e7ddf0 100644
--- a/actionpack/lib/abstract_controller/collector.rb
+++ b/actionpack/lib/abstract_controller/collector.rb
@@ -16,6 +16,10 @@ module AbstractController
generate_method_for_mime(mime)
end
+ Mime::Type.register_callback do |mime|
+ generate_method_for_mime(mime) unless self.instance_methods.include?(mime.to_sym)
+ end
+
protected
def method_missing(symbol, &block)
diff --git a/actionpack/lib/abstract_controller/translation.rb b/actionpack/lib/abstract_controller/translation.rb
index 6d68cf4944..b6c484d188 100644
--- a/actionpack/lib/abstract_controller/translation.rb
+++ b/actionpack/lib/abstract_controller/translation.rb
@@ -1,6 +1,12 @@
module AbstractController
module Translation
def translate(*args)
+ key = args.first
+ if key.is_a?(String) && (key[0] == '.')
+ key = "#{ controller_path.gsub('/', '.') }.#{ action_name }#{ key }"
+ args[0] = key
+ end
+
I18n.translate(*args)
end
alias :t :translate
@@ -10,4 +16,4 @@ module AbstractController
end
alias :l :localize
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
index 39da15e26a..73291ce083 100644
--- a/actionpack/lib/action_controller/caching/sweeping.rb
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -68,14 +68,14 @@ module ActionController #:nodoc:
def after(controller)
self.controller = controller
callback(:after) if controller.perform_caching
- # Clean up, so that the controller can be collected after this request
- self.controller = nil
end
def around(controller)
before(controller)
yield
after(controller)
+ ensure
+ clean_up
end
protected
@@ -90,6 +90,11 @@ module ActionController #:nodoc:
end
private
+ def clean_up
+ # Clean up, so that the controller can be collected after this request
+ self.controller = nil
+ end
+
def callback(timing)
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb
index bd768b634e..b078beb675 100644
--- a/actionpack/lib/action_controller/metal/flash.rb
+++ b/actionpack/lib/action_controller/metal/flash.rb
@@ -3,19 +3,34 @@ module ActionController #:nodoc:
extend ActiveSupport::Concern
included do
- delegate :flash, :to => :request
- delegate :alert, :notice, :to => "request.flash"
- helper_method :alert, :notice
+ class_attribute :_flash_types, instance_accessor: false
+ self._flash_types = []
+
+ delegate :flash, to: :request
+ add_flash_types(:alert, :notice)
end
- protected
- def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
- if alert = response_status_and_flash.delete(:alert)
- flash[:alert] = alert
+ module ClassMethods
+ def add_flash_types(*types)
+ types.each do |type|
+ next if _flash_types.include?(type)
+
+ define_method(type) do
+ request.flash[type]
+ end
+ helper_method type
+
+ _flash_types << type
end
+ end
+ end
- if notice = response_status_and_flash.delete(:notice)
- flash[:notice] = notice
+ protected
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
+ self.class._flash_types.each do |flash_type|
+ if type = response_status_and_flash.delete(flash_type)
+ flash[flash_type] = type
+ end
end
if other_flashes = response_status_and_flash.delete(:flash)
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index a0d1064094..d84588d3df 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -229,9 +229,9 @@ module ActionController
end
def decode_credentials(header)
- Hash[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
+ HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
key, value = pair.split('=', 2)
- [key.strip.to_sym, value.to_s.gsub(/^"|"$/,'').delete('\'')]
+ [key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')]
end]
end
@@ -436,10 +436,12 @@ module ActionController
values = Hash[$1.split(',').map do |value|
value.strip! # remove any spaces between commas and values
key, value = value.split(/\=\"?/) # split key=value pairs
- value.chomp!('"') # chomp trailing " in value
- value.gsub!(/\\\"/, '"') # unescape remaining quotes
- [key, value]
- end]
+ if value
+ value.chomp!('"') # chomp trailing " in value
+ value.gsub!(/\\\"/, '"') # unescape remaining quotes
+ [key, value]
+ end
+ end.compact]
[values.delete("token"), values.with_indifferent_access]
end
end
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 0b800c3c62..4665fea91a 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -182,7 +182,8 @@ module ActionController #:nodoc:
# end
# end
#
- # Be sure to check respond_with and respond_to documentation for more examples.
+ # Be sure to check the documentation of +respond_with+ and
+ # <tt>ActionController::MimeResponds.respond_to</tt> for more examples.
def respond_to(*mimes, &block)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index f01f4b99a9..bdf6e88699 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -9,8 +9,7 @@ module ActionController
:status, :location, :content_type, :to => "@_response"
def dispatch(action, request)
- @_response = ActionDispatch::Response.new
- @_response.request = request
+ set_response!(request)
super(action, request)
end
@@ -22,5 +21,12 @@ module ActionController
def reset_session
@_request.reset_session
end
+
+ private
+
+ def set_response!(request)
+ @_response = ActionDispatch::Response.new
+ @_response.request = request
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
index 83407846dc..d9c89a74f1 100644
--- a/actionpack/lib/action_controller/metal/responder.rb
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -90,7 +90,7 @@ module ActionController #:nodoc:
#
# def create
# @project = Project.find(params[:project_id])
- # @task = @project.comments.build(params[:task])
+ # @task = @project.tasks.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with(@project, @task, :status => 201)
# end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index eeb37db2e7..9f3c997024 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -139,9 +139,6 @@ module ActionController #:nodoc:
# session or flash after the template starts rendering will not propagate
# to the client.
#
- # If you try to modify cookies, session or flash, an <tt>ActionDispatch::ClosedError</tt>
- # will be raised, showing those objects are closed for modification.
- #
# == Middlewares
#
# Middlewares that need to manipulate the body won't work with streaming.
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index d1813ee745..0377b8c4cf 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -4,30 +4,25 @@ module ActionController
include RackDelegation
- def recycle!
- @_url_options = nil
- end
-
-
- # TODO: Clean this up
- def process_with_new_base_test(request, response)
- @_request = request
- @_response = response
- @_response.request = request
- ret = process(request.parameters[:action])
- if cookies = @_request.env['action_dispatch.cookies']
- cookies.write(@_response)
- end
- @_response.prepare!
- ret
- end
-
# TODO : Rewrite tests using controller.headers= to use Rack env
def headers=(new_headers)
@_response ||= ActionDispatch::Response.new
@_response.headers.replace(new_headers)
end
+ # Behavior specific to functional tests
+ module Functional # :nodoc:
+ def set_response!(request)
+ end
+
+ def recycle!
+ @_url_options = nil
+ self.response_body = nil
+ self.formats = nil
+ self.params = nil
+ end
+ end
+
module ClassMethods
def before_filters
_process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index a1f29ea1bc..5f50bf5de6 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -143,6 +143,9 @@ module ActionController
end
class TestRequest < ActionDispatch::TestRequest #:nodoc:
+ DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
+ DEFAULT_ENV.delete 'PATH_INFO'
+
def initialize(env = {})
super
@@ -150,10 +153,6 @@ module ActionController
self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => SecureRandom.hex(16))
end
- class Result < ::Array #:nodoc:
- def to_s() join '/' end
- end
-
def assign_parameters(routes, controller_path, action, parameters = {})
parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
extra_keys = routes.extra_keys(parameters)
@@ -171,7 +170,7 @@ module ActionController
non_path_parameters[key] = value
else
if value.is_a?(Array)
- value = Result.new(value.map(&:to_param))
+ value = value.map(&:to_param)
else
value = value.to_param
end
@@ -211,6 +210,12 @@ module ActionController
cookie_jar.update(@set_cookies)
cookie_jar.recycle!
end
+
+ private
+
+ def default_env
+ DEFAULT_ENV
+ end
end
class TestResponse < ActionDispatch::TestResponse
@@ -353,7 +358,7 @@ module ActionController
# Use AS::TestCase for the base class when describing a model
register_spec_type(self) do |desc|
- desc < ActionController::Base
+ Class === desc && desc < ActionController::Base
end
module Behavior
@@ -430,8 +435,13 @@ module ActionController
end
# Executes a request simulating HEAD HTTP method and set/volley the response
- def head(action, parameters = nil, session = nil, flash = nil)
- process(action, "HEAD", parameters, session, flash)
+ def head(action, *args)
+ process(action, "HEAD", *args)
+ end
+
+ # Executes a request simulating OPTIONS HTTP method and set/volley the response
+ def options(action, *args)
+ process(action, "OPTIONS", *args)
end
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@@ -471,13 +481,17 @@ module ActionController
# proper params, as is the case when engaging rack.
parameters = paramify_values(parameters) if html_format?(parameters)
+ @html_document = nil
+
+ unless @controller.respond_to?(:recycle!)
+ @controller.extend(Testing::Functional)
+ @controller.class.class_eval { include Testing }
+ end
+
@request.recycle!
@response.recycle!
- @controller.response_body = nil
- @controller.formats = nil
- @controller.params = nil
+ @controller.recycle!
- @html_document = nil
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
@@ -490,26 +504,34 @@ module ActionController
@request.session.update(session) if session
@request.session["flash"] = @request.flash.update(flash || {})
- @controller.request = @request
+ @controller.request = @request
+ @controller.response = @response
+
build_request_uri(action, parameters)
- @controller.class.class_eval { include Testing }
- @controller.recycle!
- @controller.process_with_new_base_test(@request, @response)
+
+ name = @request.parameters[:action]
+
+ @controller.process(name)
+
+ if cookies = @request.env['action_dispatch.cookies']
+ cookies.write(@response)
+ end
+ @response.prepare!
+
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
@request.session.delete('flash') if @request.session['flash'].blank?
@response
end
def setup_controller_request_and_response
- @request = TestRequest.new
- @response = TestResponse.new
+ @request = TestRequest.new
+ @response = TestResponse.new
+ @response.request = @request
if klass = self.class.controller_class
@controller ||= klass.new rescue nil
end
- @request.env.delete('PATH_INFO')
-
if defined?(@controller) && @controller
@controller.request = @request
@controller.params = {}
@@ -523,7 +545,7 @@ module ActionController
setup :setup_controller_request_and_response
end
- private
+ private
def check_required_ivars
# Sanity check for required instance variables so we can give an
# understandable error message.
@@ -564,8 +586,7 @@ module ActionController
def html_format?(parameters)
return true unless parameters.is_a?(Hash)
- format = Mime[parameters[:format]]
- format.nil? || format.html?
+ Mime.fetch(parameters[:format]) { Mime['html'] }.html?
end
end
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index ee1913dbf9..fe39c220a5 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -29,6 +29,11 @@ module Mime
Type.lookup_by_extension(type.to_s)
end
+ def self.fetch(type)
+ return type if type.is_a?(Type)
+ EXTENSION_LOOKUP.fetch(type.to_s) { |k| yield k }
+ end
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
@@ -53,6 +58,8 @@ module Mime
cattr_reader :browser_generated_types
attr_reader :symbol
+ @register_callbacks = []
+
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
@@ -84,6 +91,10 @@ module Mime
TRAILING_STAR_REGEXP = /(text|application)\/\*/
PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/
+ def register_callback(&block)
+ @register_callbacks << block
+ end
+
def lookup(string)
LOOKUP[string]
end
@@ -101,10 +112,15 @@ module Mime
def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
Mime.const_set(symbol.upcase, Type.new(string, symbol, mime_type_synonyms))
- SET << Mime.const_get(symbol.upcase)
+ new_mime = Mime.const_get(symbol.upcase)
+ SET << new_mime
([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup
([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last }
+
+ @register_callbacks.each do |callback|
+ callback.call(new_mime)
+ end
end
def parse(accept_header)
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 8cea17c7a6..1377e53ce8 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -119,9 +119,9 @@ module ActionDispatch
end
# Is this a HEAD request?
- # Equivalent to <tt>request.method_symbol == :head</tt>.
+ # Equivalent to <tt>request.request_method_symbol == :head</tt>.
def head?
- HTTP_METHOD_LOOKUP[method] == :head
+ HTTP_METHOD_LOOKUP[request_method] == :head
end
# Provides access to the request's HTTP headers, for example:
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index b903f98761..0f0589a844 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -1,5 +1,7 @@
require 'action_dispatch/http/request'
require 'action_dispatch/middleware/exception_wrapper'
+require 'action_dispatch/routing/inspector'
+
module ActionDispatch
# This middleware is responsible for logging exceptions and
@@ -7,8 +9,9 @@ module ActionDispatch
class DebugExceptions
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
- def initialize(app)
- @app = app
+ def initialize(app, routes_app = nil)
+ @app = app
+ @routes_app = routes_app
end
def call(env)
@@ -39,7 +42,8 @@ module ActionDispatch
:exception => wrapper.exception,
:application_trace => wrapper.application_trace,
:framework_trace => wrapper.framework_trace,
- :full_trace => wrapper.full_trace
+ :full_trace => wrapper.full_trace,
+ :routes => formatted_routes(exception)
)
file = "rescues/#{wrapper.rescue_template}"
@@ -78,5 +82,13 @@ module ActionDispatch
def stderr_logger
@stderr_logger ||= ActiveSupport::Logger.new($stderr)
end
+
+ def formatted_routes(exception)
+ return false unless @routes_app.respond_to?(:routes)
+ if exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)
+ inspector = ActionDispatch::Routing::RoutesInspector.new
+ inspector.format(@routes_app.routes.routes).join("\n")
+ end
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/head.rb b/actionpack/lib/action_dispatch/middleware/head.rb
deleted file mode 100644
index f1906a3ab3..0000000000
--- a/actionpack/lib/action_dispatch/middleware/head.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module ActionDispatch
- class Head
- def initialize(app)
- @app = app
- end
-
- def call(env)
- if env["REQUEST_METHOD"] == "HEAD"
- env["REQUEST_METHOD"] = "GET"
- env["rack.methodoverride.original_method"] = "HEAD"
- status, headers, _ = @app.call(env)
- [status, headers, []]
- else
- @app.call(env)
- end
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
index 177d383e94..8c594c1523 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
@@ -10,8 +10,14 @@
</ol>
</p>
<% end %>
+<%= render :template => "rescues/_trace" %>
+
+<h2>
+ Routes
+</h2>
+
<p>
- Try running <code>rake routes</code> for more information on available routes.
+ Routes match in priority from top to bottom
</p>
-<%= render :template => "rescues/_trace" %>
+<p><pre><%= @routes %></pre></p>
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
new file mode 100644
index 0000000000..bc7229b6a1
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -0,0 +1,121 @@
+require 'delegate'
+
+module ActionDispatch
+ module Routing
+ class RouteWrapper < SimpleDelegator
+ def endpoint
+ rack_app ? rack_app.inspect : "#{controller}##{action}"
+ end
+
+ def constraints
+ requirements.except(:controller, :action)
+ end
+
+ def rack_app(app = self.app)
+ @rack_app ||= begin
+ class_name = app.class.name.to_s
+ if class_name == "ActionDispatch::Routing::Mapper::Constraints"
+ rack_app(app.app)
+ elsif ActionDispatch::Routing::Redirect === app || class_name !~ /^ActionDispatch::Routing/
+ app
+ end
+ end
+ end
+
+ def verb
+ super.source.gsub(/[$^]/, '')
+ end
+
+ def path
+ super.spec.to_s
+ end
+
+ def name
+ super.to_s
+ end
+
+ def reqs
+ @reqs ||= begin
+ reqs = endpoint
+ reqs += " #{constraints.inspect}" unless constraints.empty?
+ reqs
+ end
+ end
+
+ def controller
+ requirements[:controller] || ':controller'
+ end
+
+ def action
+ requirements[:action] || ':action'
+ end
+
+ def internal?
+ path =~ %r{/rails/info.*|^#{Rails.application.config.assets.prefix}}
+ end
+
+ def engine?
+ rack_app && rack_app.respond_to?(:routes)
+ end
+ end
+
+ ##
+ # This class is just used for displaying route information when someone
+ # executes `rake routes`. People should not use this class.
+ class RoutesInspector # :nodoc:
+ def initialize
+ @engines = Hash.new
+ end
+
+ def format(all_routes, filter = nil)
+ if filter
+ all_routes = all_routes.select{ |route| route.defaults[:controller] == filter }
+ end
+
+ routes = collect_routes(all_routes)
+
+ formatted_routes(routes) +
+ formatted_routes_for_engines
+ end
+
+ def collect_routes(routes)
+ routes = routes.collect do |route|
+ RouteWrapper.new(route)
+ end.reject do |route|
+ route.internal?
+ end.collect do |route|
+ collect_engine_routes(route)
+
+ {:name => route.name, :verb => route.verb, :path => route.path, :reqs => route.reqs }
+ end
+ end
+
+ def collect_engine_routes(route)
+ name = route.endpoint
+ return unless route.engine?
+ return if @engines[name]
+
+ routes = route.rack_app.routes
+ if routes.is_a?(ActionDispatch::Routing::RouteSet)
+ @engines[name] = collect_routes(routes.routes)
+ end
+ end
+
+ def formatted_routes_for_engines
+ @engines.map do |name, routes|
+ ["\nRoutes for #{name}:"] + formatted_routes(routes)
+ end.flatten
+ end
+
+ def formatted_routes(routes)
+ name_width = routes.map{ |r| r[:name].length }.max
+ verb_width = routes.map{ |r| r[:verb].length }.max
+ path_width = routes.map{ |r| r[:path].length }.max
+
+ routes.map do |r|
+ "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 53a4afecb3..0a65b4dbcc 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -262,7 +262,7 @@ module ActionDispatch
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
path = Journey::Router::Utils.normalize_path(path)
- path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^)]+\)$}
path
end
@@ -430,6 +430,10 @@ module ActionDispatch
if options
path = options.delete(:at)
else
+ unless Hash === app
+ raise ArgumentError, "must be called with mount point"
+ end
+
options = app
app, path = options.find { |k, v| k.respond_to?(:call) }
options.delete(app) if app
@@ -913,7 +917,7 @@ module ActionDispatch
@path = (options[:path] || @name).to_s
@controller = (options[:controller] || @name).to_s
@as = options[:as]
- @param = options[:param] || :id
+ @param = (options[:param] || :id).to_sym
@options = options
end
@@ -961,12 +965,18 @@ module ActionDispatch
"#{path}/:#{param}"
end
+ alias :shallow_scope :member_scope
+
def new_scope(new_path)
"#{path}/#{new_path}"
end
+ def nested_param
+ :"#{singular}_#{param}"
+ end
+
def nested_scope
- "#{path}/:#{singular}_#{param}"
+ "#{path}/:#{nested_param}"
end
end
@@ -1477,18 +1487,18 @@ module ActionDispatch
def nested_options #:nodoc:
options = { :as => parent_resource.member_name }
options[:constraints] = {
- :"#{parent_resource.singular}_id" => id_constraint
- } if id_constraint?
+ parent_resource.nested_param => param_constraint
+ } if param_constraint?
options
end
- def id_constraint? #:nodoc:
- @scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)
+ def param_constraint? #:nodoc:
+ @scope[:constraints] && @scope[:constraints][parent_resource.param].is_a?(Regexp)
end
- def id_constraint #:nodoc:
- @scope[:constraints][:id]
+ def param_constraint #:nodoc:
+ @scope[:constraints][parent_resource.param]
end
def canonical_action?(action, flag) #:nodoc:
@@ -1501,7 +1511,7 @@ module ActionDispatch
def path_for_action(action, path) #:nodoc:
prefix = shallow_scoping? ?
- "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path]
+ "#{@scope[:shallow_path]}/#{parent_resource.shallow_scope}" : @scope[:path]
if canonical_action?(action, path.blank?)
prefix.to_s
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 1d6ca0c78d..0bbed6cbea 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -333,7 +333,7 @@ module ActionDispatch
end
end
- MountedHelpers.class_eval <<-RUBY
+ MountedHelpers.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def #{name}
@#{name} ||= _#{name}
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index fd3bed7e8f..f4c708ea33 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -102,7 +102,7 @@ module ActionDispatch
super
end
- # Hook overriden in controller to add request information
+ # Hook overridden in controller to add request information
# with `default_url_options`. Application logic should not
# go into url_options.
def url_options
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 41fa3a4b95..9de545b3c5 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -127,16 +127,13 @@ module ActionDispatch
# with a new RouteSet instance.
#
# The new instance is yielded to the passed block. Typically the block
- # will create some routes using <tt>map.draw { map.connect ... }</tt>:
+ # will create some routes using <tt>set.draw { match ... }</tt>:
#
# with_routing do |set|
- # set.draw do |map|
- # map.connect ':controller/:action/:id'
- # assert_equal(
- # ['/content/10/show', {}],
- # map.generate(:controller => 'content', :id => 10, :action => 'show')
- # end
+ # set.draw do
+ # resources :users
# end
+ # assert_equal "/users", users_path
# end
#
def with_routing
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index a86b510719..639ae6f398 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -12,7 +12,7 @@ module ActionDispatch
def initialize(env = {})
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
- super(DEFAULT_ENV.merge(env))
+ super(default_env.merge(env))
self.host = 'test.host'
self.remote_addr = '0.0.0.0'
@@ -69,5 +69,11 @@ module ActionDispatch
def cookies
@cookies ||= {}.with_indifferent_access
end
+
+ private
+
+ def default_env
+ DEFAULT_ENV
+ end
end
end
diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb
index 245849d706..ee263df484 100644
--- a/actionpack/lib/action_view/context.rb
+++ b/actionpack/lib/action_view/context.rb
@@ -26,11 +26,11 @@ module ActionView
# Encapsulates the interaction with the view flow so it
# returns the correct buffer on +yield+. This is usually
- # overwriten by helpers to add more behavior.
+ # overwritten by helpers to add more behavior.
# :api: plugin
def _layout_for(name=nil)
name ||= :layout
view_flow.get(name).html_safe
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 02c1250c76..68b0195700 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -95,7 +95,7 @@ module ActionView
# have SSL certificates for each of the asset hosts this technique allows you
# to avoid warnings in the client about mixed media.
#
- # ActionController::Base.asset_host = Proc.new { |source, request|
+ # config.action_controller.asset_host = Proc.new { |source, request|
# if request.ssl?
# "#{request.protocol}#{request.host_with_port}"
# else
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 397738dd98..9186855319 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -134,7 +134,7 @@ module ActionView
#
# <%# Add some other content, or use a different template: %>
#
- # <% content_for :navigation, true do %>
+ # <% content_for :navigation, flush: true do %>
# <li><%= link_to 'Login', :action => 'login' %></li>
# <% end %>
#
@@ -148,14 +148,14 @@ module ActionView
#
# WARNING: content_for is ignored in caches. So you shouldn't use it
# for elements that will be fragment cached.
- def content_for(name, content = nil, flush = false, &block)
+ def content_for(name, content = nil, options = {}, &block)
if content || block_given?
if block_given?
- flush = content if content
+ options = content if content
content = capture(&block)
end
if content
- flush ? @view_flow.set(name, content) : @view_flow.append(name, content)
+ options[:flush] ? @view_flow.set(name, content) : @view_flow.append(name, content)
end
nil
else
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index eef426703d..c88af0355f 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -353,7 +353,7 @@ module ActionView
html_attributes[:disabled] = 'disabled' if disabled && option_value_selected?(value, disabled)
html_attributes[:value] = value
- content_tag(:option, text, html_attributes)
+ content_tag_string(:option, text, html_attributes)
end.join("\n").html_safe
end
@@ -711,7 +711,7 @@ module ActionView
def option_html_attributes(element)
return {} unless Array === element
- Hash[element.select { |e| Hash === e }.reduce({}, :merge).map { |k, v| [k, ERB::Util.html_escape(v.to_s)] }]
+ Hash[element.select { |e| Hash === e }.reduce({}, :merge).map { |k, v| [k, v] }]
end
def option_text_and_value(option)
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 1a0019a48c..d7d9c45120 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -382,11 +382,18 @@ module ActionView
# Creates a submit button with the text <tt>value</tt> as the caption.
#
# ==== Options
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
+ # * <tt>:disabled</tt> - If true, the user will not be able to use this input.
+ # * Any other key creates standard HTML options for the tag.
+ #
+ # ==== Data attributes
+ #
# * <tt>:confirm => 'question?'</tt> - If present the unobtrusive JavaScript
# drivers will provide a prompt with the question specified. If the user accepts,
# the form is processed normally, otherwise no action is taken.
- # * <tt>:disabled</tt> - If true, the user will not be able to use this input.
- # * Any other key creates standard HTML options for the tag.
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
+ # disabled version of the submit button when the form is submitted. This feature is
+ # provided by the unobtrusive JavaScript driver.
#
# ==== Examples
# submit_tag
@@ -407,13 +414,21 @@ module ActionView
# submit_tag "Edit", :class => "edit_button"
# # => <input class="edit_button" name="commit" type="submit" value="Edit" />
#
- # submit_tag "Save", :confirm => "Are you sure?"
+ # submit_tag "Save", :data => { :confirm => "Are you sure?" }
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
#
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
+ if disable_with = options.delete("disable_with")
+ ActiveSupport::Deprecation.warn ":disable_with option is deprecated and will be removed from Rails 4.1. Use ':data => { :disable_with => \'Text\' }' instead"
+
+ options["data-disable-with"] = disable_with
+ end
+
if confirm = options.delete("confirm")
+ ActiveSupport::Deprecation.warn ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead'"
+
options["data-confirm"] = confirm
end
@@ -428,13 +443,21 @@ module ActionView
# so this helper will also accept a block.
#
# ==== Options
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
+ # * <tt>:disabled</tt> - If true, the user will not be able to
+ # use this input.
+ # * Any other key creates standard HTML options for the tag.
+ #
+ # ==== Data attributes
+ #
# * <tt>:confirm => 'question?'</tt> - If present, the
# unobtrusive JavaScript drivers will provide a prompt with
# the question specified. If the user accepts, the form is
# processed normally, otherwise no action is taken.
- # * <tt>:disabled</tt> - If true, the user will not be able to
- # use this input.
- # * Any other key creates standard HTML options for the tag.
+ # * <tt>:disable_with</tt> - Value of this parameter will be
+ # used as the value for a disabled version of the submit
+ # button when the form is submitted. This feature is provided
+ # by the unobtrusive JavaScript driver.
#
# ==== Examples
# button_tag
@@ -447,12 +470,23 @@ module ActionView
# # <strong>Ask me!</strong>
# # </button>
#
+ # button_tag "Checkout", :data => { disable_with => "Please wait..." }
+ # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
+ #
def button_tag(content_or_options = nil, options = nil, &block)
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
options ||= {}
options = options.stringify_keys
+ if disable_with = options.delete("disable_with")
+ ActiveSupport::Deprecation.warn ":disable_with option is deprecated and will be removed from Rails 4.1. Use ':data => { :disable_with => \'Text\' }' instead"
+
+ options["data-disable-with"] = disable_with
+ end
+
if confirm = options.delete("confirm")
+ ActiveSupport::Deprecation.warn ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead'"
+
options["data-confirm"] = confirm
end
@@ -466,11 +500,15 @@ module ActionView
# <tt>source</tt> is passed to AssetTagHelper#path_to_image
#
# ==== Options
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
+ # * Any other key creates standard HTML options for the tag.
+ #
+ # ==== Data attributes
+ #
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
# prompt with the question specified. If the user accepts, the form is
# processed normally, otherwise no action is taken.
- # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
- # * Any other key creates standard HTML options for the tag.
#
# ==== Examples
# image_submit_tag("login.png")
@@ -485,12 +523,14 @@ module ActionView
# image_submit_tag("agree.png", :disabled => true, :class => "agree_disagree_button")
# # => <input class="agree_disagree_button" disabled="disabled" src="/images/agree.png" type="image" />
#
- # image_submit_tag("save.png", :confirm => "Are you sure?")
+ # image_submit_tag("save.png", :data => { :confirm => "Are you sure?" })
# # => <input src="/images/save.png" data-confirm="Are you sure?" type="image" />
def image_submit_tag(source, options = {})
options = options.stringify_keys
if confirm = options.delete("confirm")
+ ActiveSupport::Deprecation.warn ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead'"
+
options["data-confirm"] = confirm
end
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index e077cd5b3c..192f5eebaa 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -137,10 +137,10 @@ module ActionView
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
+ option_tags = content_tag_string('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
end
if value.blank? && options[:prompt]
- option_tags = content_tag('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags
+ option_tags = content_tag_string('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags
end
option_tags
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 736f9fa2f0..3d86790a8f 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -132,8 +132,7 @@ module ActionView
# # posts_path
#
# link_to(body, url_options = {}, html_options = {})
- # # url_options, except :confirm or :method,
- # # is passed to url_for
+ # # url_options, except :method, is passed to url_for
#
# link_to(options = {}, html_options = {}) do
# # name
@@ -144,9 +143,7 @@ module ActionView
# end
#
# ==== Options
- # * <tt>:confirm => 'question?'</tt> - This will allow the unobtrusive JavaScript
- # driver to prompt with the question specified. If the user accepts, the link is
- # processed normally, otherwise no action is taken.
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
# * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically
# create an HTML form and immediately submit the form for processing using
# the HTTP verb specified. Useful for having links perform a POST operation
@@ -163,6 +160,16 @@ module ActionView
# completion of the Ajax request and performing JavaScript operations once
# they're complete
#
+ # ==== Data attributes
+ #
+ # * <tt>:confirm => 'question?'</tt> - This will allow the unobtrusive JavaScript
+ # driver to prompt with the question specified. If the user accepts, the link is
+ # processed normally, otherwise no action is taken.
+ # * <tt>:disable_with</tt> - Value of this parameter will be
+ # used as the value for a disabled version of the submit
+ # button when the form is submitted. This feature is provided
+ # by the unobtrusive JavaScript driver.
+ #
# ==== Examples
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
# and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
@@ -226,13 +233,15 @@ module ActionView
# link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux")
# # => <a href="/searches?foo=bar&amp;baz=quux">Nonsense search</a>
#
- # The two options specific to +link_to+ (<tt>:confirm</tt> and <tt>:method</tt>) are used as follows:
+ # The only option specific to +link_to+ (<tt>:method</tt>) is used as follows:
#
- # link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?"
- # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?"">Visit Other Site</a>
+ # link_to("Destroy", "http://www.example.com", :method => :delete)
+ # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
#
- # link_to("Destroy", "http://www.example.com", :method => :delete, :confirm => "Are you sure?")
- # # => <a href='http://www.example.com' rel="nofollow" data-method="delete" data-confirm="Are you sure?">Destroy</a>
+ # You can also use custom data attributes using the <tt>:data</tt> option:
+ #
+ # link_to "Visit Other Site", "http://www.rubyonrails.org/", :data => { :confirm => "Are you sure?" }
+ # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?"">Visit Other Site</a>
def link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options = options, name if block_given?
options ||= {}
@@ -255,10 +264,9 @@ module ActionView
# to allow styling of the form itself and its children. This can be changed
# using the <tt>:form_class</tt> modifier within +html_options+. You can control
# the form submission and input element behavior using +html_options+.
- # This method accepts the <tt>:method</tt> and <tt>:confirm</tt> modifiers
- # described in the +link_to+ documentation. If no <tt>:method</tt> modifier
- # is given, it will default to performing a POST operation. You can also
- # disable the button by passing <tt>:disabled => true</tt> in +html_options+.
+ # This method accepts the <tt>:method</tt> modifier described in the +link_to+ documentation.
+ # If no <tt>:method</tt> modifier is given, it will default to performing a POST operation.
+ # You can also disable the button by passing <tt>:disabled => true</tt> in +html_options+.
# If you are using RESTful routes, you can pass the <tt>:method</tt>
# to change the HTTP verb used to submit the form.
#
@@ -269,15 +277,23 @@ module ActionView
# * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
# <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
# * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
- # * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
- # prompt with the question specified. If the user accepts, the link is
- # processed normally, otherwise no action is taken.
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
# submit behavior. By default this behavior is an ajax submit.
# * <tt>:form</tt> - This hash will be form attributes
# * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
# be placed
#
+ # ==== Data attributes
+ #
+ # * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
+ # prompt with the question specified. If the user accepts, the link is
+ # processed normally, otherwise no action is taken.
+ # * <tt>:disable_with</tt> - Value of this parameter will be
+ # used as the value for a disabled version of the submit
+ # button when the form is submitted. This feature is provided
+ # by the unobtrusive JavaScript driver.
+ #
# ==== Examples
# <%= button_to "New", :action => "new" %>
# # => "<form method="post" action="/controller/new" class="button_to">
@@ -311,7 +327,7 @@ module ActionView
#
#
# <%= button_to "Delete Image", { :action => "delete", :id => @image.id },
- # :confirm => "Are you sure?", :method => :delete %>
+ # :method => :delete, :data => { :confirm => "Are you sure?" } %>
# # => "<form method="post" action="/images/delete/1" class="button_to">
# # <div>
# # <input type="hidden" name="_method" value="delete" />
@@ -321,12 +337,12 @@ module ActionView
# # </form>"
#
#
- # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
- # :method => "delete", :remote => true) %>
+ # <%= button_to('Destroy', 'http://www.example.com',
+ # :method => "delete", :remote => true, :data => { :confirm' => 'Are you sure?', :disable_with => 'loading...' }) %>
# # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
# # <div>
# # <input name='_method' value='delete' type='hidden' />
- # # <input value='Destroy' type='submit' data-confirm='Are you sure?' />
+ # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# # </div>
# # </form>"
@@ -627,12 +643,24 @@ module ActionView
html_options = html_options.stringify_keys
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
+ disable_with = html_options.delete("disable_with")
confirm = html_options.delete('confirm')
method = html_options.delete('method')
- html_options["data-confirm"] = confirm if confirm
+ if confirm
+ ActiveSupport::Deprecation.warn ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead"
+
+ html_options["data-confirm"] = confirm
+ end
+
add_method_to_attributes!(html_options, method) if method
+ if disable_with
+ ActiveSupport::Deprecation.warn ":disable_with option is deprecated and will be removed from Rails 4.1. Use ':data => { :disable_with => \'Text\' }' instead"
+
+ html_options["data-disable-with"] = disable_with
+ end
+
html_options
else
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 00989ec405..47dd932c71 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -96,7 +96,7 @@ module ActionView
# Helpers related to template lookup using the lookup context information.
module ViewPaths
- attr_reader :view_paths
+ attr_reader :view_paths, :html_fallback_for_js
# Whenever setting view paths, makes a copy so we can manipulate then in
# instance objects as we wish.
@@ -184,7 +184,10 @@ module ActionView
def formats=(values)
if values
values.concat(default_formats) if values.delete "*/*"
- values << :html if values == [:js]
+ if values == [:js]
+ values << :html
+ @html_fallback_for_js = true
+ end
end
super(values)
end
diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb
index e3d8e9d508..6fb8cbb46c 100644
--- a/actionpack/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb
@@ -22,5 +22,11 @@ module ActionView
def instrument(name, options={})
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
end
+
+ def prepend_formats(formats)
+ formats = Array(formats)
+ return if formats.empty? || @lookup_context.html_fallback_for_js
+ @lookup_context.formats = formats | @lookup_context.formats
+ end
end
end
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 9100545718..a08a566b35 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -320,6 +320,8 @@ module ActionView
@block = block
@details = extract_details(options)
+ prepend_formats(options[:formats])
+
if String === partial
@object = options[:object]
@path = partial
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index 3c1b11396a..156ad4e547 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -8,9 +8,10 @@ module ActionView
template = determine_template(options)
context = @lookup_context
+ prepend_formats(template.formats)
+
unless context.rendered_format
- context.formats = template.formats unless template.formats.empty?
- context.rendered_format = context.formats.first
+ context.rendered_format = template.formats.first || formats.last
end
render_template(template, options[:layout], options[:locals])
diff --git a/actionpack/test/abstract/translation_test.rb b/actionpack/test/abstract/translation_test.rb
index 0194ee943f..99064a8b87 100644
--- a/actionpack/test/abstract/translation_test.rb
+++ b/actionpack/test/abstract/translation_test.rb
@@ -23,4 +23,17 @@ class TranslationControllerTest < ActiveSupport::TestCase
def test_action_controller_base_responds_to_l
assert_respond_to @controller, :l
end
+
+ def test_lazy_lookup
+ expected = 'bar'
+ @controller.stubs(:action_name => :index)
+ I18n.stubs(:translate).with('action_controller.base.index.foo').returns(expected)
+ assert_equal expected, @controller.t('.foo')
+ end
+
+ def test_default_translation
+ key, expected = 'one.two' 'bar'
+ I18n.stubs(:translate).with(key).returns(expected)
+ assert_equal expected, @controller.t(key)
+ end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 37deb9c98a..8c7f6474e5 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -171,7 +171,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
middleware.use "ActionDispatch::ParamsParser"
middleware.use "ActionDispatch::Cookies"
middleware.use "ActionDispatch::Flash"
- middleware.use "ActionDispatch::Head"
+ middleware.use "Rack::Head"
yield(middleware) if block_given?
end
end
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index b9cb93f0f4..afc00a3c9d 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -505,6 +505,10 @@ class FilterTest < ActionController::TestCase
def show
render :text => 'hello world'
end
+
+ def error
+ raise StandardError.new
+ end
end
class ImplicitActionsController < ActionController::Base
@@ -534,6 +538,13 @@ class FilterTest < ActionController::TestCase
assert_equal 'hello world', response.body
end
+ def test_sweeper_should_clean_up_if_exception_is_raised
+ assert_raise StandardError do
+ test_process(SweeperTestController, 'error')
+ end
+ assert_nil AppSweeper.instance.controller
+ end
+
def test_before_method_of_sweeper_should_always_return_true
sweeper = ActionController::Caching::Sweeper.send(:new)
assert sweeper.before(TestController.new)
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index e4b34125ad..8340aab4d2 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -90,6 +90,10 @@ class FlashTest < ActionController::TestCase
def redirect_with_other_flashes
redirect_to '/wonderland', :flash => { :joyride => "Horses!" }
end
+
+ def redirect_with_foo_flash
+ redirect_to "/wonderland", :foo => 'for great justice'
+ end
end
tests TestController
@@ -203,6 +207,12 @@ class FlashTest < ActionController::TestCase
get :redirect_with_other_flashes
assert_equal "Horses!", @controller.send(:flash)[:joyride]
end
+
+ def test_redirect_to_with_adding_flash_types
+ @controller.class.add_flash_types :foo
+ get :redirect_with_foo_flash
+ assert_equal "for great justice", @controller.send(:flash)[:foo]
+ end
end
class FlashIntegrationTest < ActionDispatch::IntegrationTest
@@ -210,9 +220,7 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33'
class TestController < ActionController::Base
- def dont_set_flash
- head :ok
- end
+ add_flash_types :bar
def set_flash
flash["that"] = "hello"
@@ -227,6 +235,11 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
def use_flash
render :inline => "flash: #{flash["that"]}"
end
+
+ def set_bar
+ flash[:bar] = "for great justice"
+ head :ok
+ end
end
def test_flash
@@ -266,6 +279,14 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
end
end
+ def test_added_flash_types_method
+ with_test_route_set do
+ get '/set_bar'
+ assert_response :success
+ assert_equal 'for great justice', @controller.bar
+ end
+ end
+
private
# Overwrite get to send SessionSecret in env hash
diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb
index 3054c1684c..ad4e743be8 100644
--- a/actionpack/test/controller/http_token_authentication_test.rb
+++ b/actionpack/test/controller/http_token_authentication_test.rb
@@ -79,6 +79,14 @@ class HttpTokenAuthenticationTest < ActionController::TestCase
end
end
+ test "authentication request with badly formatted header" do
+ @request.env['HTTP_AUTHORIZATION'] = "Token foobar"
+ get :index
+
+ assert_response :unauthorized
+ assert_equal "HTTP Token: Access denied.\n", @response.body, "Authentication header was not properly parsed"
+ end
+
test "authentication request without credential" do
get :display
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index bdcd5561a8..c8e036b116 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -505,7 +505,7 @@ class RespondToControllerTest < ActionController::TestCase
end
class RespondWithController < ActionController::Base
- respond_to :html, :json
+ respond_to :html, :json, :touch
respond_to :xml, :except => :using_resource_with_block
respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ]
@@ -623,12 +623,14 @@ class RespondWithControllerTest < ActionController::TestCase
super
@request.host = "www.example.com"
Mime::Type.register_alias('text/html', :iphone)
+ Mime::Type.register_alias('text/html', :touch)
Mime::Type.register('text/x-mobile', :mobile)
end
def teardown
super
Mime::Type.unregister(:iphone)
+ Mime::Type.unregister(:touch)
Mime::Type.unregister(:mobile)
end
diff --git a/actionpack/test/controller/new_base/render_action_test.rb b/actionpack/test/controller/new_base/render_action_test.rb
index aa44e0b282..475bf9d3c9 100644
--- a/actionpack/test/controller/new_base/render_action_test.rb
+++ b/actionpack/test/controller/new_base/render_action_test.rb
@@ -86,8 +86,6 @@ module RenderAction
def setup
end
- describe "Both <controller_path>.html.erb and application.html.erb are missing"
-
test "rendering with layout => true" do
assert_raise(ArgumentError) do
get "/render_action/basic/hello_world_with_layout", {}, "action_dispatch.show_exceptions" => false
@@ -154,8 +152,6 @@ module RenderActionWithApplicationLayout
end
class LayoutTest < Rack::TestCase
- describe "Only application.html.erb is present and <controller_path>.html.erb is missing"
-
test "rendering implicit application.html.erb as layout" do
get "/render_action_with_application_layout/basic/hello_world"
@@ -232,8 +228,6 @@ module RenderActionWithControllerLayout
end
class ControllerLayoutTest < Rack::TestCase
- describe "Only <controller_path>.html.erb is present and application.html.erb is missing"
-
test "render hello_world and implicitly use <controller_path>.html.erb as a layout." do
get "/render_action_with_controller_layout/basic/hello_world"
@@ -290,8 +284,6 @@ module RenderActionWithBothLayouts
end
class ControllerLayoutTest < Rack::TestCase
- describe "Both <controller_path>.html.erb and application.html.erb are present"
-
test "rendering implicitly use <controller_path>.html.erb over application.html.erb as a layout" do
get "/render_action_with_both_layouts/basic/hello_world"
diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb
index 00c7df2af8..156d87c321 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -160,8 +160,6 @@ module RenderTemplate
end
class TestWithLayout < Rack::TestCase
- describe "Rendering with :template using implicit or explicit layout"
-
test "rendering with implicit layout" do
with_routing do |set|
set.draw { get ':controller', :action => :index }
diff --git a/actionpack/test/controller/new_base/render_text_test.rb b/actionpack/test/controller/new_base/render_text_test.rb
index f8d02e8b6c..d6c3926a4d 100644
--- a/actionpack/test/controller/new_base/render_text_test.rb
+++ b/actionpack/test/controller/new_base/render_text_test.rb
@@ -63,8 +63,6 @@ module RenderText
end
class RenderTextTest < Rack::TestCase
- describe "Rendering text using render :text"
-
test "rendering text from an action with default options renders the text with the layout" do
with_routing do |set|
set.draw { get ':controller', :action => 'index' }
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 49137946fe..8990fc34d6 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -197,6 +197,11 @@ XML
assert_raise(NoMethodError) { head :test_params, "document body", :id => 10 }
end
+ def test_options
+ options :test_params
+ assert_equal 200, @response.status
+ end
+
def test_process_without_flash
process :set_flash
assert_equal '><', flash['test']
@@ -635,7 +640,7 @@ XML
get :test_params, :path => ['hello', 'world']
assert_equal ['hello', 'world'], @request.path_parameters['path']
- assert_equal 'hello/world', @request.path_parameters['path'].to_s
+ assert_equal 'hello/world', @request.path_parameters['path'].to_param
end
end
@@ -913,4 +918,4 @@ class AnonymousControllerTest < ActionController::TestCase
get :index
assert_equal 'anonymous', @response.body
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb
index 8070bdec8a..58457b0c28 100644
--- a/actionpack/test/dispatch/mapper_test.rb
+++ b/actionpack/test/dispatch/mapper_test.rb
@@ -98,6 +98,15 @@ module ActionDispatch
mapper.get '/*path', :to => 'pages#show', :format => true
assert_equal '/*path.:format', fakeset.conditions.first[:path_info]
end
+
+ def test_raising_helpful_error_on_invalid_arguments
+ fakeset = FakeSet.new
+ mapper = Mapper.new fakeset
+ app = lambda { |env| [200, {}, [""]] }
+ assert_raises ArgumentError do
+ mapper.mount app
+ end
+ end
end
end
end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 9d77c3acc5..ed012093a7 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -118,6 +118,20 @@ class MimeTypeTest < ActiveSupport::TestCase
end
end
+ test "register callbacks" do
+ begin
+ registered_mimes = []
+ Mime::Type.register_callback do |mime|
+ registered_mimes << mime
+ end
+
+ Mime::Type.register("text/foo", :foo)
+ assert_equal registered_mimes, [Mime::FOO]
+ ensure
+ Mime::Type.unregister(:FOO)
+ end
+ end
+
test "custom type with extension aliases" do
begin
Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 54fc1b208d..a434e49dbd 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -461,14 +461,6 @@ class RequestTest < ActiveSupport::TestCase
end
end
- test "head masquerading as get" do
- request = stub_request 'REQUEST_METHOD' => 'GET', "rack.methodoverride.original_method" => "HEAD"
- assert_equal "HEAD", request.method
- assert_equal "GET", request.request_method
- assert request.get?
- assert request.head?
- end
-
test "post masquerading as patch" do
request = stub_request 'REQUEST_METHOD' => 'PATCH', "rack.methodoverride.original_method" => "POST"
assert_equal "POST", request.method
diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb
new file mode 100644
index 0000000000..97fc4f3e4b
--- /dev/null
+++ b/actionpack/test/dispatch/routing/inspector_test.rb
@@ -0,0 +1,170 @@
+require 'minitest/autorun'
+require 'action_controller'
+require 'rails/engine'
+require 'action_dispatch/routing/inspector'
+
+module ActionDispatch
+ module Routing
+ class RoutesInspectorTest < ActiveSupport::TestCase
+ def setup
+ @set = ActionDispatch::Routing::RouteSet.new
+ @inspector = ActionDispatch::Routing::RoutesInspector.new
+ app = ActiveSupport::OrderedOptions.new
+ app.config = ActiveSupport::OrderedOptions.new
+ app.config.assets = ActiveSupport::OrderedOptions.new
+ app.config.assets.prefix = '/sprockets'
+ Rails.stubs(:application).returns(app)
+ Rails.stubs(:env).returns("development")
+ end
+
+ def draw(&block)
+ @set.draw(&block)
+ @inspector.format(@set.routes)
+ end
+
+ def test_displaying_routes_for_engines
+ engine = Class.new(Rails::Engine) do
+ def self.to_s
+ "Blog::Engine"
+ end
+ end
+ engine.routes.draw do
+ get '/cart', :to => 'cart#show'
+ end
+
+ output = draw do
+ get '/custom/assets', :to => 'custom_assets#show'
+ mount engine => "/blog", :as => "blog"
+ end
+
+ expected = [
+ "custom_assets GET /custom/assets(.:format) custom_assets#show",
+ " blog /blog Blog::Engine",
+ "\nRoutes for Blog::Engine:",
+ "cart GET /cart(.:format) cart#show"
+ ]
+ assert_equal expected, output
+ end
+
+ def test_cart_inspect
+ output = draw do
+ get '/cart', :to => 'cart#show'
+ end
+ assert_equal ["cart GET /cart(.:format) cart#show"], output
+ end
+
+ def test_inspect_shows_custom_assets
+ output = draw do
+ get '/custom/assets', :to => 'custom_assets#show'
+ end
+ assert_equal ["custom_assets GET /custom/assets(.:format) custom_assets#show"], output
+ end
+
+ def test_inspect_routes_shows_resources_route
+ output = draw do
+ resources :articles
+ end
+ expected = [
+ " articles GET /articles(.:format) articles#index",
+ " POST /articles(.:format) articles#create",
+ " new_article GET /articles/new(.:format) articles#new",
+ "edit_article GET /articles/:id/edit(.:format) articles#edit",
+ " article GET /articles/:id(.:format) articles#show",
+ " PATCH /articles/:id(.:format) articles#update",
+ " PUT /articles/:id(.:format) articles#update",
+ " DELETE /articles/:id(.:format) articles#destroy" ]
+ assert_equal expected, output
+ end
+
+ def test_inspect_routes_shows_root_route
+ output = draw do
+ root :to => 'pages#main'
+ end
+ assert_equal ["root GET / pages#main"], output
+ end
+
+ def test_inspect_routes_shows_dynamic_action_route
+ output = draw do
+ get 'api/:action' => 'api'
+ end
+ assert_equal [" GET /api/:action(.:format) api#:action"], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_only_route
+ output = draw do
+ get ':controller/:action'
+ end
+ assert_equal [" GET /:controller/:action(.:format) :controller#:action"], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_route_with_constraints
+ output = draw do
+ get ':controller(/:action(/:id))', :id => /\d+/
+ end
+ assert_equal [" GET /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"], output
+ end
+
+ def test_rake_routes_shows_route_with_defaults
+ output = draw do
+ get 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'}
+ end
+ assert_equal [%Q[ GET /photos/:id(.:format) photos#show {:format=>"jpg"}]], output
+ end
+
+ def test_rake_routes_shows_route_with_constraints
+ output = draw do
+ get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/
+ end
+ assert_equal [" GET /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"], output
+ end
+
+ class RackApp
+ def self.call(env)
+ end
+ end
+
+ def test_rake_routes_shows_route_with_rack_app
+ output = draw do
+ get 'foo/:id' => RackApp, :id => /[A-Z]\d{5}/
+ end
+ assert_equal [" GET /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"], output
+ end
+
+ def test_rake_routes_shows_route_with_rack_app_nested_with_dynamic_constraints
+ constraint = Class.new do
+ def to_s
+ "( my custom constraint )"
+ end
+ end
+
+ output = draw do
+ scope :constraint => constraint.new do
+ mount RackApp => '/foo'
+ end
+ end
+
+ assert_equal [" /foo #{RackApp.name} {:constraint=>( my custom constraint )}"], output
+ end
+
+ def test_rake_routes_dont_show_app_mounted_in_assets_prefix
+ output = draw do
+ get '/sprockets' => RackApp
+ end
+ assert_no_match(/RackApp/, output.first)
+ assert_no_match(/\/sprockets/, output.first)
+ end
+
+ def test_redirect
+ output = draw do
+ get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" }
+ get "/bar" => redirect(path: "/foo/bar", status: 307)
+ get "/foobar" => redirect{ "/foo/bar" }
+ end
+
+ assert_equal " foo GET /foo(.:format) redirect(301, /foo/bar) {:subdomain=>\"admin\"}", output[0]
+ assert_equal " bar GET /bar(.:format) redirect(307, path: /foo/bar)", output[1]
+ assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2]
+ end
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index fed26d89f8..205238990e 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -482,11 +482,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get :preview, :on => :member
end
- resources :profiles, :param => :username do
+ resources :profiles, :param => :username, :username => /[a-z]+/ do
get :details, :on => :member
resources :messages
end
+ resources :orders do
+ constraints :download => /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/ do
+ resources :downloads, :param => :download, :shallow => true
+ end
+ end
+
scope :as => "routes" do
get "/c/:id", :as => :collision, :to => "collision#show"
get "/collision", :to => "collision#show"
@@ -2243,6 +2249,23 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '34', @request.params[:id]
end
+ def test_custom_param_constraint
+ get '/profiles/bob1'
+ assert_equal 404, @response.status
+
+ get '/profiles/bob1/details'
+ assert_equal 404, @response.status
+
+ get '/profiles/bob1/messages/34'
+ assert_equal 404, @response.status
+ end
+
+ def test_shallow_custom_param
+ get '/downloads/0c0c0b68-d24b-11e1-a861-001ff3fffe6f.zip'
+ assert_equal 'downloads#show', @response.body
+ assert_equal '0c0c0b68-d24b-11e1-a861-001ff3fffe6f', @request.params[:download]
+ end
+
private
def with_https
old_https = https?
@@ -2679,3 +2702,30 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
end
end
end
+
+class TestOptionalRootSegments < ActionDispatch::IntegrationTest
+ stub_controllers do |routes|
+ Routes = routes
+ Routes.draw do
+ get '/(page/:page)', :to => 'pages#index', :as => :root
+ end
+ end
+
+ def app
+ Routes
+ end
+
+ include Routes.url_helpers
+
+ def test_optional_root_segments
+ get '/'
+ assert_equal 'pages#index', @response.body
+ assert_equal '/', root_path
+
+ get '/page/1'
+ assert_equal 'pages#index', @response.body
+ assert_equal '1', @request.params[:page]
+ assert_equal '/page/1', root_path('1')
+ assert_equal '/page/1', root_path(:page => '1')
+ end
+end
diff --git a/actionpack/test/fixtures/project.rb b/actionpack/test/fixtures/project.rb
index 2b53d39ed5..c124a9e605 100644
--- a/actionpack/test/fixtures/project.rb
+++ b/actionpack/test/fixtures/project.rb
@@ -1,3 +1,3 @@
class Project < ActiveRecord::Base
- has_and_belongs_to_many :developers, :uniq => true
+ has_and_belongs_to_many :developers, -> { uniq }
end
diff --git a/actionpack/test/fixtures/reply.rb b/actionpack/test/fixtures/reply.rb
index 0d3b0a7c98..16b53be18a 100644
--- a/actionpack/test/fixtures/reply.rb
+++ b/actionpack/test/fixtures/reply.rb
@@ -1,6 +1,6 @@
class Reply < ActiveRecord::Base
scope :base, -> { scoped }
- belongs_to :topic, :include => [:replies]
+ belongs_to :topic, -> { includes(:replies) }
belongs_to :developer
validates_presence_of :content
diff --git a/actionpack/test/fixtures/test/_changing_priority.html.erb b/actionpack/test/fixtures/test/_changing_priority.html.erb
new file mode 100644
index 0000000000..3225efc49a
--- /dev/null
+++ b/actionpack/test/fixtures/test/_changing_priority.html.erb
@@ -0,0 +1 @@
+HTML \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_changing_priority.json.erb b/actionpack/test/fixtures/test/_changing_priority.json.erb
new file mode 100644
index 0000000000..7fa41dce66
--- /dev/null
+++ b/actionpack/test/fixtures/test/_changing_priority.json.erb
@@ -0,0 +1 @@
+JSON \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_first_json_partial.json.erb b/actionpack/test/fixtures/test/_first_json_partial.json.erb
new file mode 100644
index 0000000000..790ee896db
--- /dev/null
+++ b/actionpack/test/fixtures/test/_first_json_partial.json.erb
@@ -0,0 +1 @@
+<%= render :partial => "test/second_json_partial" %> \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_json_change_priority.json.erb b/actionpack/test/fixtures/test/_json_change_priority.json.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionpack/test/fixtures/test/_json_change_priority.json.erb
diff --git a/actionpack/test/fixtures/test/_second_json_partial.json.erb b/actionpack/test/fixtures/test/_second_json_partial.json.erb
new file mode 100644
index 0000000000..5ebb7f1afd
--- /dev/null
+++ b/actionpack/test/fixtures/test/_second_json_partial.json.erb
@@ -0,0 +1 @@
+Third level \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/change_priorty.html.erb b/actionpack/test/fixtures/test/change_priorty.html.erb
new file mode 100644
index 0000000000..5618977d05
--- /dev/null
+++ b/actionpack/test/fixtures/test/change_priorty.html.erb
@@ -0,0 +1,2 @@
+<%= render :partial => "test/json_change_priority", formats: :json %>
+HTML Template, but <%= render :partial => "test/changing_priority" %> partial \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/html_template.html.erb b/actionpack/test/fixtures/test/html_template.html.erb
new file mode 100644
index 0000000000..1bbc2b7f09
--- /dev/null
+++ b/actionpack/test/fixtures/test/html_template.html.erb
@@ -0,0 +1 @@
+<%= render :partial => "test/first_json_partial", formats: :json %> \ No newline at end of file
diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb
index 24511df444..86bccdfade 100644
--- a/actionpack/test/template/active_model_helper_test.rb
+++ b/actionpack/test/template/active_model_helper_test.rb
@@ -41,6 +41,19 @@ class ActiveModelHelperTest < ActionView::TestCase
)
end
+ def test_select_with_errors
+ assert_dom_equal(
+ %(<div class="field_with_errors"><select name="post[author_name]" id="post_author_name"><option value="a">a</option>\n<option value="b">b</option></select></div>),
+ select("post", "author_name", [:a, :b])
+ )
+ end
+
+ def test_select_with_errors_and_blank_option
+ expected_dom = %(<div class="field_with_errors"><select name="post[author_name]" id="post_author_name"><option value="">Choose one...</option>\n<option value="a">a</option>\n<option value="b">b</option></select></div>)
+ assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :include_blank => 'Choose one...'))
+ assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :prompt => 'Choose one...'))
+ end
+
def test_date_select_with_errors
assert_dom_equal(
%(<div class="field_with_errors"><select id="post_updated_at_1i" name="post[updated_at(1i)]">\n<option selected="selected" value="2004">2004</option>\n<option value="2005">2005</option>\n</select>\n<input id="post_updated_at_2i" name="post[updated_at(2i)]" type="hidden" value="6" />\n<input id="post_updated_at_3i" name="post[updated_at(3i)]" type="hidden" value="1" />\n</div>),
@@ -82,4 +95,5 @@ class ActiveModelHelperTest < ActionView::TestCase
ensure
ActionView::Base.field_error_proc = old_proc if old_proc
end
+
end
diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb
index 17469f8c3e..234ac3252d 100644
--- a/actionpack/test/template/capture_helper_test.rb
+++ b/actionpack/test/template/capture_helper_test.rb
@@ -56,7 +56,7 @@ class CaptureHelperTest < ActionView::TestCase
def test_content_for_with_multiple_calls_and_flush
assert ! content_for?(:title)
content_for :title, 'foo'
- content_for :title, 'bar', true
+ content_for :title, 'bar', flush: true
assert_equal 'bar', content_for(:title)
end
@@ -75,7 +75,7 @@ class CaptureHelperTest < ActionView::TestCase
content_for :title do
'foo'
end
- content_for :title, true do
+ content_for :title, flush: true do
'bar'
end
assert_equal 'bar', content_for(:title)
@@ -86,7 +86,7 @@ class CaptureHelperTest < ActionView::TestCase
content_for :title do
'foo'
end
- content_for :title, nil, true do
+ content_for :title, nil, flush: true do
'bar'
end
assert_equal 'bar', content_for(:title)
@@ -97,7 +97,7 @@ class CaptureHelperTest < ActionView::TestCase
content_for :title do
'foo'
end
- content_for :title, false do
+ content_for :title, flush: false do
'bar'
end
assert_equal 'foobar', content_for(:title)
@@ -117,11 +117,11 @@ class CaptureHelperTest < ActionView::TestCase
def test_content_for_with_whitespace_block_and_flush
assert ! content_for?(:title)
content_for :title, 'foo'
- content_for :title, true do
+ content_for :title, flush: true do
output_buffer << " \n "
nil
end
- content_for :title, 'bar', true
+ content_for :title, 'bar', flush: true
assert_equal 'bar', content_for(:title)
end
@@ -131,9 +131,9 @@ class CaptureHelperTest < ActionView::TestCase
assert_equal nil, content_for(:title) { output_buffer << 'bar'; nil }
assert_equal nil, content_for(:title) { output_buffer << " \n "; nil }
assert_equal 'foobar', content_for(:title)
- assert_equal nil, content_for(:title, 'foo', true)
- assert_equal nil, content_for(:title, true) { output_buffer << 'bar'; nil }
- assert_equal nil, content_for(:title, true) { output_buffer << " \n "; nil }
+ assert_equal nil, content_for(:title, 'foo', flush: true)
+ assert_equal nil, content_for(:title, flush: true) { output_buffer << 'bar'; nil }
+ assert_equal nil, content_for(:title, flush: true) { output_buffer << " \n "; nil }
assert_equal 'bar', content_for(:title)
end
diff --git a/actionpack/test/template/erb/tag_helper_test.rb b/actionpack/test/template/erb/tag_helper_test.rb
index 1724d6432d..84e328d8be 100644
--- a/actionpack/test/template/erb/tag_helper_test.rb
+++ b/actionpack/test/template/erb/tag_helper_test.rb
@@ -3,9 +3,6 @@ require "template/erb/helper"
module ERBTest
class TagHelperTest < BlockTestCase
-
- extend ActiveSupport::Testing::Declarative
-
test "percent equals works for content_tag and does not require parenthesis on method call" do
assert_equal "<div>Hello world</div>", render_content("content_tag :div", "Hello world")
end
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 2322fb0406..bfc73172eb 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -1130,6 +1130,20 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_options_for_select_with_data_element
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\" data-test=\"bold\">&lt;Denmark&gt;</option>",
+ options_for_select([ [ "<Denmark>", { :data => { :test => 'bold' } } ] ])
+ )
+ end
+
+ def test_options_for_select_with_data_element_with_special_characters
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\" data-test=\"&lt;bold&gt;\">&lt;Denmark&gt;</option>",
+ options_for_select([ [ "<Denmark>", { :data => { :test => '<bold>' } } ] ])
+ )
+ end
+
def test_options_for_select_with_element_attributes_and_selection
assert_dom_equal(
"<option value=\"&lt;Denmark&gt;\">&lt;Denmark&gt;</option>\n<option value=\"USA\" class=\"bold\" selected=\"selected\">USA</option>\n<option value=\"Sweden\">Sweden</option>",
@@ -1144,6 +1158,13 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_options_for_select_with_special_characters
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\" onclick=\"alert(&quot;&lt;code&gt;&quot;)\">&lt;Denmark&gt;</option>",
+ options_for_select([ [ "<Denmark>", { :onclick => %(alert("<code>")) } ] ])
+ )
+ end
+
def test_option_html_attributes_from_without_hash
assert_equal(
{},
@@ -1172,13 +1193,6 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
- def test_option_html_attributes_with_special_characters
- assert_equal(
- {:onclick => "alert(&quot;&lt;code&gt;&quot;)"},
- option_html_attributes([ 'foo', 'bar', { :onclick => %(alert("<code>")) } ])
- )
- end
-
def test_grouped_collection_select
@post = Post.new
@post.origin = 'dk'
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 5d19e3274d..9afa4a2927 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -375,17 +375,33 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!')" type="submit" value="Save" />),
- submit_tag("Save", 'data-disable-with' => "Saving...", :onclick => "alert('hello!')")
+ submit_tag("Save", :onclick => "alert('hello!')", :data => { :disable_with => "Saving..." })
+ )
+ end
+
+ def test_submit_tag_with_no_onclick_options
+ assert_dom_equal(
+ %(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
+ submit_tag("Save", :data => { :disable_with => "Saving..." })
)
end
def test_submit_tag_with_confirmation
assert_dom_equal(
%(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />),
- submit_tag("Save", :confirm => "Are you sure?")
+ submit_tag("Save", :data => { :confirm => "Are you sure?" })
)
end
+ def test_submit_tag_with_deprecated_confirmation
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />),
+ submit_tag("Save", :confirm => "Are you sure?")
+ )
+ end
+ end
+
def test_button_tag
assert_dom_equal(
%(<button name="button" type="submit">Button</button>),
@@ -437,13 +453,39 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal('<button name="temptation" type="button"><strong>Do not press me</strong></button>', output)
end
+ def test_button_tag_with_confirmation
+ assert_dom_equal(
+ %(<button name="button" type="submit" data-confirm="Are you sure?">Save</button>),
+ button_tag("Save", :type => "submit", :data => { :confirm => "Are you sure?" })
+ )
+ end
+
+ def test_button_tag_with_deprecated_confirmation
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ %(<button name="button" type="submit" data-confirm="Are you sure?">Save</button>),
+ button_tag("Save", :type => "submit", :confirm => "Are you sure?")
+ )
+ end
+ end
+
def test_image_submit_tag_with_confirmation
assert_dom_equal(
%(<input type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
- image_submit_tag("save.gif", :confirm => "Are you sure?")
+ image_submit_tag("save.gif", :data => { :confirm => "Are you sure?" })
)
end
+ def test_image_submit_tag_with_deprecated_confirmation
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ %(<input type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
+ image_submit_tag("save.gif", :confirm => "Are you sure?")
+ )
+ end
+ end
+
+
def test_color_field_tag
expected = %{<input id="car" name="car" type="color" />}
assert_dom_equal(expected, color_field_tag("car"))
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 88ed8664c2..3ce1d20bd9 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -54,6 +54,16 @@ module RenderTestCases
assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html])
end
+ def test_render_partial_implicitly_use_format_of_the_rendered_partial
+ @view.lookup_context.formats = [:html]
+ assert_equal "Third level", @view.render(:template => "test/html_template")
+ end
+
+ def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names
+ @view.lookup_context.formats = [:html]
+ assert_equal "\nHTML Template, but JSON partial", @view.render(:template => "test/change_priorty")
+ end
+
def test_render_template_with_a_missing_partial_of_another_format
@view.lookup_context.formats = [:html]
assert_raise ActionView::Template::Error, "Missing partial /missing with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder]}" do
diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb
index c005f040eb..387aafebd4 100644
--- a/actionpack/test/template/test_case_test.rb
+++ b/actionpack/test/template/test_case_test.rb
@@ -68,14 +68,14 @@ module ActionView
assert_nil self.class.determine_default_helper_class("String")
end
- test "delegates notice to request.flash" do
- view.request.flash.expects(:notice).with("this message")
- view.notice("this message")
+ test "delegates notice to request.flash[:notice]" do
+ view.request.flash.expects(:[]).with(:notice)
+ view.notice
end
- test "delegates alert to request.flash" do
- view.request.flash.expects(:alert).with("this message")
- view.alert("this message")
+ test "delegates alert to request.flash[:alert]" do
+ view.request.flash.expects(:[]).with(:alert)
+ view.alert
end
test "uses controller lookup context" do
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 62608a727f..cb6f378ecb 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -90,17 +90,35 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_button_to_with_javascript_confirm
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
+ button_to("Hello", "http://www.example.com", :data => { :confirm => "Are you sure?" })
)
end
+ def test_button_to_with_deprecated_confirm
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
+ )
+ end
+ end
+
def test_button_to_with_javascript_disable_with
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", 'data-disable-with' => "Greeting...")
+ button_to("Hello", "http://www.example.com", :data => { :disable_with => "Greeting..." })
)
end
+ def test_button_to_with_javascript_deprecated_disable_with
+ assert_deprecated ":disable_with option is deprecated and will be removed from Rails 4.1. Use ':data => { :disable_with => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :disable_with => "Greeting...")
+ )
+ end
+ end
+
def test_button_to_with_remote_and_form_options
assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"custom-class\" data-remote=\"true\" data-type=\"json\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :remote => true, :form => { :class => "custom-class", "data-type" => "json" } )
end
@@ -108,10 +126,35 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_button_to_with_remote_and_javascript_confirm
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?")
+ button_to("Hello", "http://www.example.com", :remote => true, :data => { :confirm => "Are you sure?" })
+ )
+ end
+
+ def test_button_to_with_remote_and_javascript_with_deprecated_confirm
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?")
+ )
+ end
+ end
+
+ def test_button_to_with_remote_and_javascript_disable_with
+ assert_dom_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :remote => true, :data => { :disable_with => "Greeting..." })
)
end
+ def test_button_to_with_remote_and_javascript_deprecated_disable_with
+ assert_deprecated ":disable_with option is deprecated and will be removed from Rails 4.1. Use ':data => { :disable_with => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :remote => true, :disable_with => "Greeting...")
+ )
+ end
+ end
+
def test_button_to_with_remote_false
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>",
@@ -208,18 +251,39 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_link_tag_with_javascript_confirm
assert_dom_equal(
"<a href=\"http://www.example.com\" data-confirm=\"Are you sure?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
+ link_to("Hello", "http://www.example.com", :data => { :confirm => "Are you sure?" })
)
assert_dom_equal(
"<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure, can you?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?")
+ link_to("Hello", "http://www.example.com", :data => { :confirm => "You can't possibly be sure, can you?" })
)
assert_dom_equal(
"<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure,\n can you?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?")
+ link_to("Hello", "http://www.example.com", :data => { :confirm => "You can't possibly be sure,\n can you?" })
)
end
+ def test_link_tag_with_deprecated_confirm
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<a href=\"http://www.example.com\" data-confirm=\"Are you sure?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
+ )
+ end
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure, can you?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?")
+ )
+ end
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure,\n can you?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?")
+ )
+ end
+ end
+
def test_link_to_with_remote
assert_dom_equal(
"<a href=\"http://www.example.com\" data-remote=\"true\">Hello</a>",
@@ -265,18 +329,37 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_link_tag_using_post_javascript_and_confirm
assert_dom_equal(
"<a href=\"http://www.example.com\" data-method=\"post\" rel=\"nofollow\" data-confirm=\"Are you serious?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :method => :post, :confirm => "Are you serious?")
+ link_to("Hello", "http://www.example.com", :method => :post, :data => { :confirm => "Are you serious?" })
)
end
+ def test_link_tag_using_post_javascript_and_with_deprecated_confirm
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<a href=\"http://www.example.com\" data-method=\"post\" rel=\"nofollow\" data-confirm=\"Are you serious?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :method => :post, :confirm => "Are you serious?")
+ )
+ end
+ end
+
def test_link_tag_using_delete_javascript_and_href_and_confirm
assert_dom_equal(
"<a href='\#' rel=\"nofollow\" data-confirm=\"Are you serious?\" data-method=\"delete\">Destroy</a>",
- link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"),
+ link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :data => { :confirm => "Are you serious?" }),
"When specifying url, form should be generated with it, but not this.href"
)
end
+ def test_link_tag_using_delete_javascript_and_href_and_with_deprecated_confirm
+ assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use ':data => { :confirm => \'Text\' }' instead" do
+ assert_dom_equal(
+ "<a href='\#' rel=\"nofollow\" data-confirm=\"Are you serious?\" data-method=\"delete\">Destroy</a>",
+ link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"),
+ "When specifying url, form should be generated with it, but not this.href"
+ )
+ end
+ end
+
def test_link_tag_with_block
assert_dom_equal '<a href="/"><span>Example site</span></a>',
link_to('/') { content_tag(:span, 'Example site') }