aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md65
-rw-r--r--actionpack/README.rdoc7
-rw-r--r--actionpack/RUNNING_UNIT_TESTS.rdoc2
-rw-r--r--actionpack/lib/abstract_controller/base.rb2
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb25
-rw-r--r--actionpack/lib/action_controller/metal.rb15
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb26
-rw-r--r--actionpack/lib/action_controller/metal/live.rb50
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb6
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb14
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb23
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb40
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb6
-rw-r--r--actionpack/lib/action_controller/railtie.rb4
-rw-r--r--actionpack/lib/action_controller/test_case.rb19
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb29
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb26
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb19
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb60
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb140
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb25
-rw-r--r--actionpack/lib/action_dispatch/journey/nodes/node.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/parser.rb88
-rw-r--r--actionpack/lib/action_dispatch/journey/parser.y5
-rw-r--r--actionpack/lib/action_dispatch/journey/path/pattern.rb31
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb21
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb94
-rw-r--r--actionpack/lib/action_dispatch/journey/router/strexp.rb15
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb173
-rw-r--r--actionpack/lib/action_dispatch/journey/visualizer/index.html.erb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb9
-rw-r--r--actionpack/lib/action_dispatch/middleware/public_exceptions.rb5
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb4
-rw-r--r--actionpack/lib/action_dispatch/routing/endpoint.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb427
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb22
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb118
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb25
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb2
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/controller/assert_select_test.rb5
-rw-r--r--actionpack/test/controller/content_type_test.rb32
-rw-r--r--actionpack/test/controller/filters_test.rb380
-rw-r--r--actionpack/test/controller/http_basic_authentication_test.rb7
-rw-r--r--actionpack/test/controller/http_token_authentication_test.rb47
-rw-r--r--actionpack/test/controller/live_stream_test.rb89
-rw-r--r--actionpack/test/controller/localized_templates_test.rb18
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb13
-rw-r--r--actionpack/test/controller/mime/respond_with_test.rb33
-rw-r--r--actionpack/test/controller/new_base/bare_metal_test.rb6
-rw-r--r--actionpack/test/controller/parameters/always_permitted_parameters_test.rb29
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb19
-rw-r--r--actionpack/test/controller/params_wrapper_test.rb26
-rw-r--r--actionpack/test/controller/render_other_test.rb11
-rw-r--r--actionpack/test/controller/render_test.rb6
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb9
-rw-r--r--actionpack/test/controller/required_params_test.rb18
-rw-r--r--actionpack/test/controller/routing_test.rb36
-rw-r--r--actionpack/test/controller/send_file_test.rb3
-rw-r--r--actionpack/test/controller/test_case_test.rb18
-rw-r--r--actionpack/test/controller/url_for_test.rb22
-rw-r--r--actionpack/test/dispatch/mapper_test.rb6
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb2
-rw-r--r--actionpack/test/dispatch/mount_test.rb10
-rw-r--r--actionpack/test/dispatch/reloader_test.rb5
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb3
-rw-r--r--actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb5
-rw-r--r--actionpack/test/dispatch/request_test.rb5
-rw-r--r--actionpack/test/dispatch/response_test.rb6
-rw-r--r--actionpack/test/dispatch/routing/concerns_test.rb3
-rw-r--r--actionpack/test/dispatch/routing_test.rb289
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb18
-rw-r--r--actionpack/test/dispatch/url_generation_test.rb22
-rw-r--r--actionpack/test/journey/path/pattern_test.rb46
-rw-r--r--actionpack/test/journey/route_test.rb22
-rw-r--r--actionpack/test/journey/router/strexp_test.rb32
-rw-r--r--actionpack/test/journey/router_test.rb184
-rw-r--r--actionpack/test/journey/routes_test.rb10
84 files changed, 1949 insertions, 1236 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index be1f53faf5..2b22041b3b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,4 +1,61 @@
-* Fix 'Stack level too deep' when rendering `head :ok` in an action method
+* Generate shallow paths for all children of shallow resources.
+
+ Fixes #15783.
+
+ *Seb Jacobs*
+
+* JSONP responses are now rendered with the `text/javascript` content type
+ when rendering through a `respond_to` block.
+
+ Fixes #15081.
+
+ *Lucas Mazza*
+
+* Add `config.action_controller.always_permitted_parameters` to configure which
+ parameters are permitted globally. The default value of this configuration is
+ `['controller', 'action']`.
+
+ *Gary S. Weaver*, *Rafael Chacon*
+
+* Fix env['PATH_INFO'] missing leading slash when a rack app mounted at '/'.
+
+ Fixes #15511.
+
+ *Larry Lv*
+
+* ActionController::Parameters#require now accepts `false` values.
+
+ Fixes #15685.
+
+ *Sergio Romano*
+
+* With authorization header `Authorization: Token token=`, `authenticate` now
+ recognize token as nil, instead of "token".
+
+ Fixes #14846.
+
+ *Larry Lv*
+
+* Ensure the controller is always notified as soon as the client disconnects
+ during live streaming, even when the controller is blocked on a write.
+
+ *Nicholas Jakobsen*, *Matthew Draper*
+
+* Routes specifying 'to:' must be a string that contains a "#" or a rack
+ application. Use of a symbol should be replaced with `action: symbol`.
+ Use of a string without a "#" should be replaced with `controller: string`.
+
+* Fix URL generation with `:trailing_slash` such that it does not add
+ a trailing slash after `.:format`
+
+ *Dan Langevin*
+
+* Build full URI as string when processing path in integration tests for
+ performance reasons.
+
+ *Guo Xiang Tan*
+
+* Fix `'Stack level too deep'` when rendering `head :ok` in an action method
called 'status' in a controller.
Fixes #13905.
@@ -66,7 +123,7 @@
4. Use `escape_segment` rather than `escape_path` in URL generation
For point 4 there are two exceptions. Firstly, when a route uses wildcard segments
- (e.g. *foo) then we use `escape_path` as the value may contain '/' characters. This
+ (e.g. `*foo`) then we use `escape_path` as the value may contain '/' characters. This
means that wildcard routes can't be optimized. Secondly, if a `:controller` segment
is used in the path then this uses `escape_path` as the controller may be namespaced.
@@ -96,12 +153,12 @@
*Andrew White*, *James Coglan*
-* Append link to bad code to backtrace when exception is SyntaxError.
+* Append link to bad code to backtrace when exception is `SyntaxError`.
*Boris Kuznetsov*
* Swapped the parameters of assert_equal in `assert_select` so that the
- proper values were printed correctly
+ proper values were printed correctly.
Fixes #14422.
diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc
index 2f6575c3b5..02a24a7412 100644
--- a/actionpack/README.rdoc
+++ b/actionpack/README.rdoc
@@ -48,6 +48,11 @@ API documentation is at
* http://api.rubyonrails.org
-Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
+Bug reports can be filed for the Ruby on Rails project here:
* https://github.com/rails/rails/issues
+
+Feature requests should be discussed on the rails-core mailing list here:
+
+* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
+
diff --git a/actionpack/RUNNING_UNIT_TESTS.rdoc b/actionpack/RUNNING_UNIT_TESTS.rdoc
index 2f923136d9..f96a9d9da5 100644
--- a/actionpack/RUNNING_UNIT_TESTS.rdoc
+++ b/actionpack/RUNNING_UNIT_TESTS.rdoc
@@ -4,7 +4,7 @@ The easiest way to run the unit tests is through Rake. The default task runs
the entire test suite for all classes. For more information, check out the
full array of rake tasks with "rake -T".
-Rake can be found at http://rake.rubyforge.org.
+Rake can be found at http://docs.seattlerb.org/rake/.
== Running by hand
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index c00f0d0c6f..15faabf977 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -255,7 +255,7 @@ module AbstractController
# Checks if the action name is valid and returns false otherwise.
def _valid_action_name?(action_name)
- action_name.to_s !~ Regexp.new(File::SEPARATOR)
+ !action_name.to_s.include? File::SEPARATOR
end
end
end
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index 69aca308d6..ca5c80cd71 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -42,20 +42,18 @@ module AbstractController
end
end
- # Skip before, after, and around action callbacks matching any of the names
- # Aliased as skip_filter.
+ # Skip before, after, and around action callbacks matching any of the names.
#
# ==== Parameters
# * <tt>names</tt> - A list of valid names that could be used for
# callbacks. Note that skipping uses Ruby equality, so it's
# impossible to skip a callback defined using an anonymous proc
- # using #skip_filter
+ # using #skip_action_callback
def skip_action_callback(*names)
skip_before_action(*names)
skip_after_action(*names)
skip_around_action(*names)
end
-
alias_method :skip_filter, :skip_action_callback
# Take callback names and an optional callback proc, normalize them,
@@ -85,7 +83,6 @@ module AbstractController
# :call-seq: before_action(names, block)
#
# Append a callback before actions. See _insert_callbacks for parameter details.
- # Aliased as before_filter.
##
# :method: prepend_before_action
@@ -93,7 +90,6 @@ module AbstractController
# :call-seq: prepend_before_action(names, block)
#
# Prepend a callback before actions. See _insert_callbacks for parameter details.
- # Aliased as prepend_before_filter.
##
# :method: skip_before_action
@@ -101,7 +97,6 @@ module AbstractController
# :call-seq: skip_before_action(names)
#
# Skip a callback before actions. See _insert_callbacks for parameter details.
- # Aliased as skip_before_filter.
##
# :method: append_before_action
@@ -109,7 +104,6 @@ module AbstractController
# :call-seq: append_before_action(names, block)
#
# Append a callback before actions. See _insert_callbacks for parameter details.
- # Aliased as append_before_filter.
##
# :method: after_action
@@ -117,7 +111,6 @@ module AbstractController
# :call-seq: after_action(names, block)
#
# Append a callback after actions. See _insert_callbacks for parameter details.
- # Aliased as after_filter.
##
# :method: prepend_after_action
@@ -125,7 +118,6 @@ module AbstractController
# :call-seq: prepend_after_action(names, block)
#
# Prepend a callback after actions. See _insert_callbacks for parameter details.
- # Aliased as prepend_after_filter.
##
# :method: skip_after_action
@@ -133,7 +125,6 @@ module AbstractController
# :call-seq: skip_after_action(names)
#
# Skip a callback after actions. See _insert_callbacks for parameter details.
- # Aliased as skip_after_filter.
##
# :method: append_after_action
@@ -141,7 +132,6 @@ module AbstractController
# :call-seq: append_after_action(names, block)
#
# Append a callback after actions. See _insert_callbacks for parameter details.
- # Aliased as append_after_filter.
##
# :method: around_action
@@ -149,7 +139,6 @@ module AbstractController
# :call-seq: around_action(names, block)
#
# Append a callback around actions. See _insert_callbacks for parameter details.
- # Aliased as around_filter.
##
# :method: prepend_around_action
@@ -157,7 +146,6 @@ module AbstractController
# :call-seq: prepend_around_action(names, block)
#
# Prepend a callback around actions. See _insert_callbacks for parameter details.
- # Aliased as prepend_around_filter.
##
# :method: skip_around_action
@@ -165,7 +153,6 @@ module AbstractController
# :call-seq: skip_around_action(names)
#
# Skip a callback around actions. See _insert_callbacks for parameter details.
- # Aliased as skip_around_filter.
##
# :method: append_around_action
@@ -173,7 +160,6 @@ module AbstractController
# :call-seq: append_around_action(names, block)
#
# Append a callback around actions. See _insert_callbacks for parameter details.
- # Aliased as append_around_filter.
# set up before_action, prepend_before_action, skip_before_action, etc.
# for each of before, after, and around.
@@ -183,7 +169,6 @@ module AbstractController
set_callback(:process_action, callback, name, options)
end
end
-
alias_method :"#{callback}_filter", :"#{callback}_action"
define_method "prepend_#{callback}_action" do |*names, &blk|
@@ -191,7 +176,6 @@ module AbstractController
set_callback(:process_action, callback, name, options.merge(:prepend => true))
end
end
-
alias_method :"prepend_#{callback}_filter", :"prepend_#{callback}_action"
# Skip a before, after or around callback. See _insert_callbacks
@@ -201,12 +185,11 @@ module AbstractController
skip_callback(:process_action, callback, name, options)
end
end
-
alias_method :"skip_#{callback}_filter", :"skip_#{callback}_action"
# *_action is the same as append_*_action
- alias_method :"append_#{callback}_action", :"#{callback}_action" # alias_method :append_before_action, :before_action
- alias_method :"append_#{callback}_filter", :"#{callback}_action" # alias_method :append_before_filter, :before_action
+ alias_method :"append_#{callback}_action", :"#{callback}_action"
+ alias_method :"append_#{callback}_filter", :"#{callback}_action"
end
end
end
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 696fbf6e09..9a427ebfdb 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -30,10 +30,8 @@ module ActionController
end
end
- def build(action, app=nil, &block)
- app ||= block
+ def build(action, app = Proc.new)
action = action.to_s
- raise "MiddlewareStack#build requires an app" unless app
middlewares.reverse.inject(app) do |a, middleware|
middleware.valid?(action) ? middleware.build(a) : a
@@ -223,13 +221,18 @@ module ActionController
# Makes the controller a Rack endpoint that runs the action in the given
# +env+'s +action_dispatch.request.path_parameters+ key.
def self.call(env)
- action(env['action_dispatch.request.path_parameters'][:action]).call(env)
+ req = ActionDispatch::Request.new env
+ action(req.path_parameters[:action]).call(env)
end
# Returns a Rack endpoint for the given action name.
def self.action(name, klass = ActionDispatch::Request)
- middleware_stack.build(name.to_s) do |env|
- new.dispatch(name, klass.new(env))
+ if middleware_stack.any?
+ middleware_stack.build(name) do |env|
+ new.dispatch(name, klass.new(env))
+ end
+ else
+ lambda { |env| new.dispatch(name, klass.new(env)) }
end
end
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 2eb7853aa6..25c123edf7 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -90,17 +90,29 @@ module ActionController
end
def authenticate(request, &login_procedure)
- unless request.authorization.blank?
+ if has_basic_credentials?(request)
login_procedure.call(*user_name_and_password(request))
end
end
+ def has_basic_credentials?(request)
+ request.authorization.present? && (auth_scheme(request) == 'Basic')
+ end
+
def user_name_and_password(request)
decode_credentials(request).split(':', 2)
end
def decode_credentials(request)
- ::Base64.decode64(request.authorization.split(' ', 2).last || '')
+ ::Base64.decode64(auth_param(request) || '')
+ end
+
+ def auth_scheme(request)
+ request.authorization.split(' ', 2).first
+ end
+
+ def auth_param(request)
+ request.authorization.split(' ', 2).second
end
def encode_credentials(user_name, password)
@@ -109,8 +121,8 @@ module ActionController
def authentication_request(controller, realm)
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}")
- controller.response_body = "HTTP Basic: Access denied.\n"
controller.status = 401
+ controller.response_body = "HTTP Basic: Access denied.\n"
end
end
@@ -244,8 +256,8 @@ module ActionController
def authentication_request(controller, realm, message = nil)
message ||= "HTTP Digest: Access denied.\n"
authentication_header(controller, realm)
- controller.response_body = message
controller.status = 401
+ controller.response_body = message
end
def secret_token(request)
@@ -437,7 +449,7 @@ module ActionController
authorization_request = request.authorization.to_s
if authorization_request[TOKEN_REGEX]
params = token_params_from authorization_request
- [params.shift.last, Hash[params].with_indifferent_access]
+ [params.shift[1], Hash[params].with_indifferent_access]
end
end
@@ -452,14 +464,14 @@ module ActionController
# This removes the `"` characters wrapping the value.
def rewrite_param_values(array_params)
- array_params.each { |param| param.last.gsub! %r/^"|"$/, '' }
+ array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, '' }
end
# This method takes an authorization body and splits up the key-value
# pairs by the standardized `:`, `;`, or `\t` delimiters defined in
# `AUTHN_PAIR_DELIMITERS`.
def raw_params(auth)
- auth.sub(TOKEN_REGEX, '').split(/"\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
+ auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
end
# Encodes the given token and options into an Authorization header value.
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index 4c0554d27b..706ce04062 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -107,12 +107,25 @@ module ActionController
end
end
+ class ClientDisconnected < RuntimeError
+ end
+
class Buffer < ActionDispatch::Response::Buffer #:nodoc:
include MonitorMixin
+ # Ignore that the client has disconnected.
+ #
+ # If this value is `true`, calling `write` after the client
+ # disconnects will result in the written content being silently
+ # discarded. If this value is `false` (the default), a
+ # ClientDisconnected exception will be raised.
+ attr_accessor :ignore_disconnect
+
def initialize(response)
@error_callback = lambda { true }
@cv = new_cond
+ @aborted = false
+ @ignore_disconnect = false
super(response, SizedQueue.new(10))
end
@@ -123,6 +136,17 @@ module ActionController
end
super
+
+ unless connected?
+ @buf.clear
+
+ unless @ignore_disconnect
+ # Raise ClientDisconnected, which is a RuntimeError (not an
+ # IOError), because that's more appropriate for something beyond
+ # the developer's control.
+ raise ClientDisconnected, "client disconnected"
+ end
+ end
end
def each
@@ -133,6 +157,10 @@ module ActionController
@response.sent!
end
+ # Write a 'close' event to the buffer; the producer/writing thread
+ # uses this to notify us that it's finished supplying content.
+ #
+ # See also #abort.
def close
synchronize do
super
@@ -141,6 +169,26 @@ module ActionController
end
end
+ # Inform the producer/writing thread that the client has
+ # disconnected; the reading thread is no longer interested in
+ # anything that's being written.
+ #
+ # See also #close.
+ def abort
+ synchronize do
+ @aborted = true
+ @buf.clear
+ end
+ end
+
+ # Is the client still connected and waiting for content?
+ #
+ # The result of calling `write` when this is `false` is determined
+ # by `ignore_disconnect`.
+ def connected?
+ !@aborted
+ end
+
def await_close
synchronize do
@cv.wait_until { @closed }
@@ -157,7 +205,7 @@ module ActionController
end
class Response < ActionDispatch::Response #:nodoc: all
- class Header < DelegateClass(Hash)
+ class Header < DelegateClass(Hash) # :nodoc:
def initialize(response, header)
@response = response
super(header)
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 1974bbf529..00e7e980f8 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -322,7 +322,7 @@ module ActionController #:nodoc:
# end
# end
#
- # * for a javascript request - if the template isn't found, an exception is
+ # * for a JavaScript request - if the template isn't found, an exception is
# raised.
# * for other requests - i.e. data formats such as xml, json, csv etc, if
# the resource passed to +respond_with+ responds to <code>to_<format></code>,
@@ -335,7 +335,7 @@ module ActionController #:nodoc:
# As outlined above, the +resources+ argument passed to +respond_with+
# can play two roles. It can be used to generate the redirect url
# for successful html requests (e.g. for +create+ actions when
- # no template exists), while for formats other than html and javascript
+ # no template exists), while for formats other than html and JavaScript
# it is the object that gets rendered, by being converted directly to the
# required format (again assuming no template exists).
#
@@ -352,7 +352,7 @@ module ActionController #:nodoc:
#
# This would cause +respond_with+ to redirect to <code>project_task_url</code>
# instead of <code>task_url</code>. For request formats other than html or
- # javascript, if multiple resources are passed in this way, it is the last
+ # JavaScript, if multiple resources are passed in this way, it is the last
# one specified that is rendered.
#
# === Customizing response behavior
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 2812038938..3feb737277 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -14,7 +14,7 @@ module ActionController
include ActionController::RackDelegation
include ActionController::UrlFor
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ # Redirects the browser to the target specified in +options+. This parameter can be any one of:
#
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
@@ -24,6 +24,8 @@ module ActionController
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
+ # === Examples:
+ #
# redirect_to action: "show", id: 5
# redirect_to post
# redirect_to "http://www.rubyonrails.org"
@@ -32,7 +34,7 @@ module ActionController
# redirect_to :back
# redirect_to proc { edit_post_url(@post) }
#
- # The redirection happens as a "302 Found" header unless otherwise specified.
+ # The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
#
# redirect_to post_url(@post), status: :found
# redirect_to action: 'atom', status: :moved_permanently
@@ -60,15 +62,17 @@ module ActionController
# redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
# redirect_to({ action: 'atom' }, alert: "Something serious happened")
#
- # When using <tt>redirect_to :back</tt>, if there is no referrer, ActionController::RedirectBackError will be raised. You may specify some fallback
- # behavior for this case by rescuing ActionController::RedirectBackError.
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # <tt>ActionController::RedirectBackError</tt> will be raised. You
+ # may specify some fallback behavior for this case by rescuing
+ # <tt>ActionController::RedirectBackError</tt>.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(options)
- self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
end
def _compute_redirect_to_location(options) #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 0443b73953..ae55e6d7f5 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -6,6 +6,11 @@ module ActionController
Renderers.add(key, &block)
end
+ # See <tt>Renderers.remove</tt>
+ def self.remove_renderer(key)
+ Renderers.remove(key)
+ end
+
class MissingRenderer < LoadError
def initialize(format)
super "No renderer defined for format: #{format}"
@@ -73,7 +78,7 @@ module ActionController
# respond_to do |format|
# format.html
# format.csv { render csv: @csvable, filename: @csvable.name }
- # }
+ # end
# end
# To use renderers and their mime types in more concise ways, see
# <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
@@ -83,6 +88,17 @@ module ActionController
RENDERERS << key.to_sym
end
+ # This method is the opposite of add method.
+ #
+ # Usage:
+ #
+ # ActionController::Renderers.remove(:csv)
+ def self.remove(key)
+ RENDERERS.delete(key.to_sym)
+ method = "_render_option_#{key}"
+ remove_method(method) if method_defined?(method)
+ end
+
module All
extend ActiveSupport::Concern
include Renderers
@@ -96,7 +112,10 @@ module ActionController
json = json.to_json(options) unless json.kind_of?(String)
if options[:callback].present?
- self.content_type ||= Mime::JS
+ if self.content_type.nil? || self.content_type == Mime::JSON
+ self.content_type = Mime::JS
+ end
+
"#{options[:callback]}(#{json})"
else
self.content_type ||= Mime::JSON
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 62d5931b45..04401cad7b 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -183,7 +183,7 @@ module ActionController #:nodoc:
# You may also want to configure other parameters like <tt>:tcp_nodelay</tt>.
# Please check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen
#
- # If you are using Unicorn with Nginx, you may need to tweak Nginx.
+ # If you are using Unicorn with NGINX, you may need to tweak NGINX.
# Streaming should work out of the box on Rainbows.
#
# ==== Passenger
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index d86d49c9dc..bc27ecaa20 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/array/wrap'
+require 'active_support/deprecation'
require 'active_support/rescuable'
require 'action_dispatch/http/upload'
require 'stringio'
@@ -39,7 +40,7 @@ module ActionController
# == Action Controller \Parameters
#
# Allows to choose which attributes should be whitelisted for mass updating
- # and thus prevent accidentally exposing that which shouldn’t be exposed.
+ # and thus prevent accidentally exposing that which shouldn't be exposed.
# Provides two methods for this purpose: #require and #permit. The former is
# used to mark parameters as required. The latter is used to set the parameter
# as permitted and limit which attributes should be allowed for mass updating.
@@ -101,9 +102,23 @@ module ActionController
cattr_accessor :permit_all_parameters, instance_accessor: false
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
- # Never raise an UnpermittedParameters exception because of these params
- # are present. They are added by Rails and it's of no concern.
- NEVER_UNPERMITTED_PARAMS = %w( controller action )
+ # By default, never raise an UnpermittedParameters exception if these
+ # params are present. The default includes both 'controller' and 'action'
+ # because they are added by Rails and should be of no concern. One way
+ # to change these is to specify `always_permitted_parameters` in your
+ # config. For instance:
+ #
+ # config.always_permitted_parameters = %w( controller action format )
+ cattr_accessor :always_permitted_parameters
+ self.always_permitted_parameters = %w( controller action )
+
+ def self.const_missing(const_name)
+ super unless const_name == :NEVER_UNPERMITTED_PARAMS
+ ActiveSupport::Deprecation.warn "`ActionController::Parameters::NEVER_UNPERMITTED_PARAMS`"\
+ " has been deprecated. Use "\
+ "`ActionController::Parameters.always_permitted_parameters` instead."
+ self.always_permitted_parameters
+ end
# Returns a new instance of <tt>ActionController::Parameters</tt>.
# Also, sets the +permitted+ attribute to the default value of
@@ -129,6 +144,10 @@ module ActionController
# Attribute that keeps track of converted arrays, if any, to avoid double
# looping in the common use case permit + mass-assignment. Defined in a
# method to instantiate it only if needed.
+ #
+ # Testing membership still loops, but it's going to be faster than our own
+ # loop that converts values. Also, we are not going to build a new array
+ # object per fetch.
def converted_arrays
@converted_arrays ||= Set.new
end
@@ -158,8 +177,8 @@ module ActionController
def permit!
each_pair do |key, value|
value = convert_hashes_to_parameters(key, value)
- Array.wrap(value).each do |_|
- _.permit! if _.respond_to? :permit!
+ Array.wrap(value).each do |v|
+ v.permit! if v.respond_to? :permit!
end
end
@@ -180,7 +199,12 @@ module ActionController
# ActionController::Parameters.new(person: {}).require(:person)
# # => ActionController::ParameterMissing: param not found: person
def require(key)
- self[key].presence || raise(ParameterMissing.new(key))
+ value = self[key]
+ if value.present? || value == false
+ value
+ else
+ raise ParameterMissing.new(key)
+ end
end
# Alias of #require.
@@ -380,7 +404,7 @@ module ActionController
end
def unpermitted_keys(params)
- self.keys - params.keys - NEVER_UNPERMITTED_PARAMS
+ self.keys - params.keys - self.always_permitted_parameters
end
#
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 37d4a96ee1..07265be3fe 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -23,12 +23,12 @@ module ActionController
include AbstractController::UrlFor
def url_options
- @_url_options ||= super.reverse_merge(
+ @_url_options ||= {
:host => request.host,
:port => request.optional_port,
:protocol => request.protocol,
- :_recall => request.symbolized_path_parameters
- ).freeze
+ :_recall => request.path_parameters
+ }.merge(super).freeze
if (same_origin = _routes.equal?(env["action_dispatch.routes".freeze])) ||
(script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index a2fc814221..28b20052b5 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -23,6 +23,10 @@ module ActionController
options = app.config.action_controller
ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false }
+ if app.config.action_controller[:always_permitted_parameters]
+ ActionController::Parameters.always_permitted_parameters =
+ app.config.action_controller.delete(:always_permitted_parameters)
+ end
ActionController::Parameters.action_on_unpermitted_parameters = options.delete(:action_on_unpermitted_parameters) do
(Rails.env.test? || Rails.env.development?) ? :log : false
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index c6a8f581de..8fd11d7cf2 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -199,7 +199,7 @@ module ActionController
value = value.dup
end
- if extra_keys.include?(key.to_sym)
+ if extra_keys.include?(key)
non_path_parameters[key] = value
else
if value.is_a?(Array)
@@ -208,7 +208,7 @@ module ActionController
value = value.to_param
end
- path_parameters[key.to_s] = value
+ path_parameters[key] = value
end
end
@@ -233,7 +233,6 @@ module ActionController
@formats = nil
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
- @symbolized_path_params = nil
@method = @request_method = nil
@fullpath = @ip = @remote_ip = @protocol = nil
@env['action_dispatch.request.query_parameters'] = {}
@@ -583,6 +582,7 @@ module ActionController
end
parameters, session, flash = args
+ parameters ||= {}
# Ensure that numbers and symbols passed as params are converted to
# proper params, as is the case when engaging rack.
@@ -592,7 +592,6 @@ module ActionController
unless @controller.respond_to?(:recycle!)
@controller.extend(Testing::Functional)
- @controller.class.class_eval { include Testing }
end
@request.recycle!
@@ -601,7 +600,6 @@ module ActionController
@request.env['REQUEST_METHOD'] = http_method
- parameters ||= {}
controller_class_name = @controller.class.anonymous? ?
"anonymous" :
@controller.class.controller_path
@@ -629,8 +627,11 @@ module ActionController
@response.prepare!
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
- @request.session['flash'] = @request.flash.to_session_value
- @request.session.delete('flash') if @request.session['flash'].blank?
+
+ if flash_value = @request.flash.to_session_value
+ @request.session['flash'] = flash_value
+ end
+
@response
end
@@ -695,7 +696,7 @@ module ActionController
:only_path => true,
:action => action,
:relative_url_root => nil,
- :_recall => @request.symbolized_path_parameters)
+ :_recall => @request.path_parameters)
url, query_string = @routes.url_for(options).split("?", 2)
@@ -706,7 +707,7 @@ module ActionController
end
def html_format?(parameters)
- return true unless parameters.is_a?(Hash)
+ return true unless parameters.key?(:format)
Mime.fetch(parameters[:format]) { Mime['html'] }.html?
end
end
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index f9b278349e..63a3cbc90b 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -92,7 +92,7 @@ module ActionDispatch
LAST_MODIFIED = "Last-Modified".freeze
ETAG = "ETag".freeze
CACHE_CONTROL = "Cache-Control".freeze
- SPECIAL_KEYS = %w[extras no-cache max-age public must-revalidate]
+ SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public must-revalidate])
def cache_control_segments
if cache_control = self[CACHE_CONTROL]
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 3e607bbde1..bc5410dc38 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -6,14 +6,27 @@ module ActionDispatch
# headers = ActionDispatch::Http::Headers.new(env)
# headers["Content-Type"] # => "text/plain"
class Headers
- CGI_VARIABLES = %w(
- CONTENT_TYPE CONTENT_LENGTH
- HTTPS AUTH_TYPE GATEWAY_INTERFACE
- PATH_INFO PATH_TRANSLATED QUERY_STRING
- REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER
- REQUEST_METHOD SCRIPT_NAME
- SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE
- )
+ CGI_VARIABLES = Set.new(%W[
+ AUTH_TYPE
+ CONTENT_LENGTH
+ CONTENT_TYPE
+ GATEWAY_INTERFACE
+ HTTPS
+ PATH_INFO
+ PATH_TRANSLATED
+ QUERY_STRING
+ REMOTE_ADDR
+ REMOTE_HOST
+ REMOTE_IDENT
+ REMOTE_USER
+ REQUEST_METHOD
+ SCRIPT_NAME
+ SERVER_NAME
+ SERVER_PORT
+ SERVER_PROTOCOL
+ SERVER_SOFTWARE
+ ]).freeze
+
HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
include Enumerable
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 378dbf6354..20ae48d458 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -1,13 +1,11 @@
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/indifferent_access'
+require 'active_support/deprecation'
module ActionDispatch
module Http
module Parameters
- def initialize(env)
- super
- @symbolized_path_params = nil
- end
+ PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
# Returns both GET and POST \parameters in a single hash.
def parameters
@@ -18,34 +16,28 @@ module ActionDispatch
query_parameters.dup
end
params.merge!(path_parameters)
- params.with_indifferent_access
end
end
alias :params :parameters
def path_parameters=(parameters) #:nodoc:
- @symbolized_path_params = nil
- @env.delete("action_dispatch.request.parameters")
- @env["action_dispatch.request.path_parameters"] = parameters
+ @env.delete('action_dispatch.request.parameters')
+ @env[PARAMETERS_KEY] = parameters
end
- # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
def symbolized_path_parameters
- @symbolized_path_params ||= path_parameters.symbolize_keys
+ ActiveSupport::Deprecation.warn(
+ "`symbolized_path_parameters` is deprecated. Please use `path_parameters`"
+ )
+ path_parameters
end
# Returns a hash with the \parameters used to form the \path of the request.
# Returned hash keys are strings:
#
# {'action' => 'my_action', 'controller' => 'my_controller'}
- #
- # See <tt>symbolized_path_parameters</tt> for symbolized keys.
def path_parameters
- @env["action_dispatch.request.path_parameters"] ||= {}
- end
-
- def reset_parameters #:nodoc:
- @env.delete("action_dispatch.request.parameters")
+ @env[PARAMETERS_KEY] ||= {}
end
private
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index cdb3e44b3a..01f117be99 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -53,6 +53,17 @@ module ActionDispatch
@uuid = nil
end
+ def check_path_parameters!
+ # If any of the path parameters has an invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ path_parameters.each do |key, value|
+ next unless value.respond_to?(:valid_encoding?)
+ unless value.valid_encoding?
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
+ end
+ end
+ end
+
def key?(key)
@env.key?(key)
end
@@ -198,8 +209,8 @@ module ActionDispatch
end
# Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
- # (case-insensitive). All major JavaScript libraries send this header with
- # every Ajax request.
+ # (case-insensitive), which may need to be manually added depending on the
+ # choice of JavaScript libraries and frameworks.
def xml_http_request?
@env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
end
@@ -280,7 +291,7 @@ module ActionDispatch
# Override Rack's GET method to support indifferent access
def GET
- @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge((normalize_encode_params(super) || {}))
+ @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
rescue TypeError => e
raise ActionController::BadRequest.new(:query, e)
end
@@ -288,7 +299,7 @@ module ActionDispatch
# Override Rack's POST method to support indifferent access
def POST
- @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge((normalize_encode_params(super) || {}))
+ @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
rescue TypeError => e
raise ActionController::BadRequest.new(:request, e)
end
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index eaea93b730..2fab6be1a5 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -97,6 +97,9 @@ module ActionDispatch # :nodoc:
x
end
+ def abort
+ end
+
def close
@response.commit!
@closed = true
@@ -207,18 +210,6 @@ module ActionDispatch # :nodoc:
end
alias_method :status_message, :message
- def respond_to?(method, include_private = false)
- if method.to_s == 'to_path'
- stream.respond_to?(method)
- else
- super
- end
- end
-
- def to_path
- stream.to_path
- end
-
# Returns the content of the response as a string. This contains the contents
# of any calls to <tt>render</tt>.
def body
@@ -271,6 +262,17 @@ module ActionDispatch # :nodoc:
stream.close if stream.respond_to?(:close)
end
+ def abort
+ if stream.respond_to?(:abort)
+ stream.abort
+ elsif stream.respond_to?(:close)
+ # `stream.close` should really be reserved for a close from the
+ # other direction, but we must fall back to it for
+ # compatibility.
+ stream.close
+ end
+ end
+
# Turns the Response into a Rack-compatible array of the status, headers,
# and body.
def to_a
@@ -337,6 +339,38 @@ module ActionDispatch # :nodoc:
!@sending_file && @charset != false
end
+ class RackBody
+ def initialize(response)
+ @response = response
+ end
+
+ def each(*args, &block)
+ @response.each(*args, &block)
+ end
+
+ def close
+ # Rack "close" maps to Response#abort, and *not* Response#close
+ # (which is used when the controller's finished writing)
+ @response.abort
+ end
+
+ def body
+ @response.body
+ end
+
+ def respond_to?(method, include_private = false)
+ if method.to_s == 'to_path'
+ @response.stream.respond_to?(method)
+ else
+ super
+ end
+ end
+
+ def to_path
+ @response.stream.to_path
+ end
+ end
+
def rack_response(status, header)
assign_default_content_type_and_charset!(header)
handle_conditional_get!
@@ -347,7 +381,7 @@ module ActionDispatch # :nodoc:
header.delete CONTENT_TYPE
[status, header, []]
else
- [status, header, Rack::BodyProxy.new(self){}]
+ [status, header, RackBody.new(self)]
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index c9860af909..6ba2820d09 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -5,45 +5,47 @@ module ActionDispatch
module Http
module URL
IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
- HOST_REGEXP = /(^.*:\/\/)?([^:]+)(?::(\d+$))?/
+ HOST_REGEXP = /(^[^:]+:\/\/)?([^:]+)(?::(\d+$))?/
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
mattr_accessor :tld_length
self.tld_length = 1
class << self
- def extract_domain(host, tld_length = @@tld_length)
- host.split('.').last(1 + tld_length).join('.') if named_host?(host)
+ def extract_domain(host, tld_length)
+ extract_domain_from(host, tld_length) if named_host?(host)
end
- def extract_subdomains(host, tld_length = @@tld_length)
+ def extract_subdomains(host, tld_length)
if named_host?(host)
- parts = host.split('.')
- parts[0..-(tld_length + 2)]
+ extract_subdomains_from(host, tld_length)
else
[]
end
end
- def extract_subdomain(host, tld_length = @@tld_length)
+ def extract_subdomain(host, tld_length)
extract_subdomains(host, tld_length).join('.')
end
def url_for(options)
+ host = options[:host]
+ unless host || options[:only_path]
+ raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
+ end
+
path = options[:script_name].to_s.chomp("/")
path << options[:path].to_s
- result = build_host_url(options)
+ path = add_trailing_slash(path) if options[:trailing_slash]
- if options[:trailing_slash]
- if path.include?('?')
- result << path.sub(/\?/, '/\&')
- else
- result << path.sub(/[^\/]\z|\A\z/, '\&/')
- end
- else
- result << path
- end
+ result = if options[:only_path]
+ path
+ else
+ protocol = options[:protocol]
+ port = options[:port]
+ build_host_url(host, port, protocol, options).concat path
+ end
if options.key? :params
params = options[:params].is_a?(Hash) ?
@@ -60,50 +62,57 @@ module ActionDispatch
private
- def build_host_url(options)
- unless options[:host] || options[:only_path]
- raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
- end
+ def extract_domain_from(host, tld_length)
+ host.split('.').last(1 + tld_length).join('.')
+ end
- result = ""
+ def extract_subdomains_from(host, tld_length)
+ parts = host.split('.')
+ parts[0..-(tld_length + 2)]
+ end
- unless options[:only_path]
- if match = options[:host].match(HOST_REGEXP)
- options[:protocol] ||= match[1] unless options[:protocol] == false
- options[:host] = match[2]
- options[:port] = match[3] unless options.key?(:port)
- end
+ def add_trailing_slash(path)
+ # includes querysting
+ if path.include?('?')
+ path.sub!(/\?/, '/\&')
+ # does not have a .format
+ elsif !path.include?(".")
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
+ end
- options[:protocol] = normalize_protocol(options)
- options[:host] = normalize_host(options)
- options[:port] = normalize_port(options)
+ path
+ end
- result << options[:protocol]
- result << rewrite_authentication(options)
- result << options[:host]
- result << ":#{options[:port]}" if options[:port]
+ def build_host_url(host, port, protocol, options)
+ if match = host.match(HOST_REGEXP)
+ protocol ||= match[1] unless protocol == false
+ host = match[2]
+ port = match[3] unless options.key? :port
end
- result
- end
- def named_host?(host)
- host && IP_HOST_REGEXP !~ host
- end
+ protocol = normalize_protocol protocol
+ host = normalize_host(host, options)
- def same_host?(options)
- (options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
- end
+ result = protocol.dup
- def rewrite_authentication(options)
if options[:user] && options[:password]
- "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
- else
- ""
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
end
+
+ result << host
+ normalize_port(port, protocol) { |normalized_port|
+ result << ":#{normalized_port}"
+ }
+
+ result
+ end
+
+ def named_host?(host)
+ IP_HOST_REGEXP !~ host
end
- def normalize_protocol(options)
- case options[:protocol]
+ def normalize_protocol(protocol)
+ case protocol
when nil
"http://"
when false, "//"
@@ -111,36 +120,39 @@ module ActionDispatch
when PROTOCOL_REGEXP
"#{$1}://"
else
- raise ArgumentError, "Invalid :protocol option: #{options[:protocol].inspect}"
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
end
end
- def normalize_host(options)
- return options[:host] if !named_host?(options[:host]) || same_host?(options)
+ def normalize_host(_host, options)
+ return _host unless named_host?(_host)
tld_length = options[:tld_length] || @@tld_length
+ subdomain = options.fetch :subdomain, true
+ domain = options[:domain]
host = ""
- if options[:subdomain] == true || !options.key?(:subdomain)
- host << extract_subdomain(options[:host], tld_length).to_param
- elsif options[:subdomain].present?
- host << options[:subdomain].to_param
+ if subdomain == true
+ return _host if domain.nil?
+
+ host << extract_subdomains_from(_host, tld_length).join('.')
+ elsif subdomain
+ host << subdomain.to_param
end
host << "." unless host.empty?
- host << (options[:domain] || extract_domain(options[:host], tld_length))
+ host << (domain || extract_domain_from(_host, tld_length))
host
end
- def normalize_port(options)
- return nil if options[:port].nil? || options[:port] == false
+ def normalize_port(port, protocol)
+ return unless port
- case options[:protocol]
- when "//"
- options[:port]
+ case protocol
+ when "//" then yield port
when "https://"
- options[:port].to_i == 443 ? nil : options[:port]
+ yield port unless port.to_i == 443
else
- options[:port].to_i == 80 ? nil : options[:port]
+ yield port unless port.to_i == 80
end
end
end
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 57f0963731..6d58323789 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -12,7 +12,7 @@ module ActionDispatch
@cache = nil
end
- def generate(type, name, options, recall = {}, parameterize = nil)
+ def generate(name, options, recall = {}, parameterize = nil)
constraints = recall.merge(options)
missing_keys = []
@@ -30,6 +30,12 @@ module ActionDispatch
parameterized_parts.key?(key) || route.defaults.key?(key)
end
+ defaults = route.defaults
+ required_parts = route.required_parts
+ parameterized_parts.delete_if do |key, value|
+ value.to_s == defaults[key].to_s && !required_parts.include?(key)
+ end
+
return [route.format(parameterized_parts), params]
end
@@ -74,12 +80,12 @@ module ActionDispatch
if named_routes.key?(name)
yield named_routes[name]
else
- routes = non_recursive(cache, options.to_a)
+ routes = non_recursive(cache, options)
hash = routes.group_by { |_, r| r.score(options) }
hash.keys.sort.reverse_each do |score|
- next if score < 0
+ break if score < 0
hash[score].sort_by { |i, _| i }.each do |_, route|
yield route
@@ -90,14 +96,14 @@ module ActionDispatch
def non_recursive(cache, options)
routes = []
- stack = [cache]
+ queue = [cache]
- while stack.any?
- c = stack.shift
+ while queue.any?
+ c = queue.shift
routes.concat(c[:___routes]) if c.key?(:___routes)
options.each do |pair|
- stack << c[pair] if c.key?(pair)
+ queue << c[pair] if c.key?(pair)
end
end
@@ -126,11 +132,6 @@ module ActionDispatch
}
end
- # Returns +true+ if no missing keys are present, otherwise +false+.
- def verify_required_parts!(route, parts)
- missing_keys(route, parts).empty?
- end
-
def build_cache
root = { ___routes: [] }
routes.each_with_index do |route, i|
diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb
index 935442ef66..bb01c087bc 100644
--- a/actionpack/lib/action_dispatch/journey/nodes/node.rb
+++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb
@@ -93,6 +93,10 @@ module ActionDispatch
class Star < Unary # :nodoc:
def type; :STAR; end
+
+ def name
+ left.name.tr '*:', ''
+ end
end
class Binary < Node # :nodoc:
diff --git a/actionpack/lib/action_dispatch/journey/parser.rb b/actionpack/lib/action_dispatch/journey/parser.rb
index 430812fafe..d129ba7e16 100644
--- a/actionpack/lib/action_dispatch/journey/parser.rb
+++ b/actionpack/lib/action_dispatch/journey/parser.rb
@@ -1,7 +1,7 @@
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.4.9
-# from Racc grammar file "".
+# This file is automatically generated by Racc 1.4.11
+# from Racc grammer file "".
#
require 'racc/parser.rb'
@@ -9,42 +9,38 @@ require 'racc/parser.rb'
require 'action_dispatch/journey/parser_extras'
module ActionDispatch
- module Journey # :nodoc:
- class Parser < Racc::Parser # :nodoc:
+ module Journey
+ class Parser < Racc::Parser
##### State transition tables begin ###
racc_action_table = [
- 17, 21, 13, 15, 14, 7, nil, 16, 8, 19,
- 13, 15, 14, 7, 23, 16, 8, 19, 13, 15,
- 14, 7, nil, 16, 8, 13, 15, 14, 7, nil,
- 16, 8, 13, 15, 14, 7, nil, 16, 8 ]
+ 13, 15, 14, 7, 21, 16, 8, 19, 13, 15,
+ 14, 7, 17, 16, 8, 13, 15, 14, 7, 24,
+ 16, 8, 13, 15, 14, 7, 19, 16, 8 ]
racc_action_check = [
- 1, 17, 1, 1, 1, 1, nil, 1, 1, 1,
- 20, 20, 20, 20, 20, 20, 20, 20, 7, 7,
- 7, 7, nil, 7, 7, 19, 19, 19, 19, nil,
- 19, 19, 0, 0, 0, 0, nil, 0, 0 ]
+ 2, 2, 2, 2, 17, 2, 2, 2, 0, 0,
+ 0, 0, 1, 0, 0, 19, 19, 19, 19, 20,
+ 19, 19, 7, 7, 7, 7, 22, 7, 7 ]
racc_action_pointer = [
- 30, 0, nil, nil, nil, nil, nil, 16, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, 1, nil, 23,
- 8, nil, nil, nil ]
+ 6, 12, -2, nil, nil, nil, nil, 20, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 4, nil, 13,
+ 13, nil, 17, nil, nil ]
racc_action_default = [
- -18, -18, -2, -3, -4, -5, -6, -18, -9, -10,
- -11, -12, -13, -14, -15, -16, -17, -18, -1, -18,
- -18, 24, -8, -7 ]
+ -19, -19, -2, -3, -4, -5, -6, -19, -10, -11,
+ -12, -13, -14, -15, -16, -17, -18, -19, -1, -19,
+ -19, 25, -8, -9, -7 ]
racc_goto_table = [
- 18, 1, nil, nil, nil, nil, nil, nil, 20, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 22, 18 ]
+ 1, 22, 18, 23, nil, nil, nil, 20 ]
racc_goto_check = [
- 2, 1, nil, nil, nil, nil, nil, nil, 1, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 2, 2 ]
+ 1, 2, 1, 3, nil, nil, nil, 1 ]
racc_goto_pointer = [
- nil, 1, -1, nil, nil, nil, nil, nil, nil, nil,
+ nil, 0, -18, -16, nil, nil, nil, nil, nil, nil,
nil ]
racc_goto_default = [
@@ -61,19 +57,20 @@ racc_reduce_table = [
1, 12, :_reduce_none,
3, 15, :_reduce_7,
3, 13, :_reduce_8,
- 1, 16, :_reduce_9,
+ 3, 13, :_reduce_9,
+ 1, 16, :_reduce_10,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
- 1, 19, :_reduce_14,
- 1, 17, :_reduce_15,
- 1, 18, :_reduce_16,
- 1, 20, :_reduce_17 ]
+ 1, 19, :_reduce_15,
+ 1, 17, :_reduce_16,
+ 1, 18, :_reduce_17,
+ 1, 20, :_reduce_18 ]
-racc_reduce_n = 18
+racc_reduce_n = 19
-racc_shift_n = 24
+racc_shift_n = 25
racc_token_table = {
false => 0,
@@ -137,12 +134,12 @@ Racc_debug_parser = false
# reduce 0 omitted
def _reduce_1(val, _values, result)
- result = Cat.new(val.first, val.last)
+ result = Cat.new(val.first, val.last)
result
end
def _reduce_2(val, _values, result)
- result = val.first
+ result = val.first
result
end
@@ -155,21 +152,24 @@ end
# reduce 6 omitted
def _reduce_7(val, _values, result)
- result = Group.new(val[1])
+ result = Group.new(val[1])
result
end
def _reduce_8(val, _values, result)
- result = Or.new([val.first, val.last])
+ result = Or.new([val.first, val.last])
result
end
def _reduce_9(val, _values, result)
- result = Star.new(Symbol.new(val.last))
+ result = Or.new([val.first, val.last])
result
end
-# reduce 10 omitted
+def _reduce_10(val, _values, result)
+ result = Star.new(Symbol.new(val.last))
+ result
+end
# reduce 11 omitted
@@ -177,23 +177,25 @@ end
# reduce 13 omitted
-def _reduce_14(val, _values, result)
- result = Slash.new('/')
- result
-end
+# reduce 14 omitted
def _reduce_15(val, _values, result)
- result = Symbol.new(val.first)
+ result = Slash.new('/')
result
end
def _reduce_16(val, _values, result)
- result = Literal.new(val.first)
+ result = Symbol.new(val.first)
result
end
def _reduce_17(val, _values, result)
- result = Dot.new(val.first)
+ result = Literal.new(val.first)
+ result
+end
+
+def _reduce_18(val, _values, result)
+ result = Dot.new(val.first)
result
end
diff --git a/actionpack/lib/action_dispatch/journey/parser.y b/actionpack/lib/action_dispatch/journey/parser.y
index 040f8d5922..0ead222551 100644
--- a/actionpack/lib/action_dispatch/journey/parser.y
+++ b/actionpack/lib/action_dispatch/journey/parser.y
@@ -4,7 +4,7 @@ token SLASH LITERAL SYMBOL LPAREN RPAREN DOT STAR OR
rule
expressions
- : expressions expression { result = Cat.new(val.first, val.last) }
+ : expression expressions { result = Cat.new(val.first, val.last) }
| expression { result = val.first }
| or
;
@@ -17,7 +17,8 @@ rule
: LPAREN expressions RPAREN { result = Group.new(val[1]) }
;
or
- : expressions OR expression { result = Or.new([val.first, val.last]) }
+ : expression OR expression { result = Or.new([val.first, val.last]) }
+ | expression OR or { result = Or.new([val.first, val.last]) }
;
star
: STAR { result = Star.new(Symbol.new(val.last)) }
diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb
index fb155e516f..3af940a02f 100644
--- a/actionpack/lib/action_dispatch/journey/path/pattern.rb
+++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb
@@ -1,27 +1,20 @@
+require 'action_dispatch/journey/router/strexp'
+
module ActionDispatch
module Journey # :nodoc:
module Path # :nodoc:
class Pattern # :nodoc:
attr_reader :spec, :requirements, :anchored
- def initialize(strexp)
- parser = Journey::Parser.new
-
- @anchored = true
+ def self.from_string string
+ new Journey::Router::Strexp.build(string, {}, ["/.?"], true)
+ end
- case strexp
- when String
- @spec = parser.parse(strexp)
- @requirements = {}
- @separators = "/.?"
- when Router::Strexp
- @spec = parser.parse(strexp.path)
- @requirements = strexp.requirements
- @separators = strexp.separators.join
- @anchored = strexp.anchor
- else
- raise ArgumentError, "Bad expression: #{strexp}"
- end
+ def initialize(strexp)
+ @spec = strexp.ast
+ @requirements = strexp.requirements
+ @separators = strexp.separators.join
+ @anchored = strexp.anchor
@names = nil
@optional_names = nil
@@ -30,6 +23,10 @@ module ActionDispatch
@offsets = nil
end
+ def build_formatter
+ Visitors::FormatBuilder.new.accept(spec)
+ end
+
def ast
@spec.grep(Nodes::Symbol).each do |node|
re = @requirements[node.to_sym]
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 2b399d3ee3..9f0a3af902 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -16,14 +16,6 @@ module ActionDispatch
@app = app
@path = path
- # Unwrap any constraints so we can see what's inside for route generation.
- # This allows the formatter to skip over any mounted applications or redirects
- # that shouldn't be matched when using a url_for without a route name.
- while app.is_a?(Routing::Mapper::Constraints) do
- app = app.app
- end
- @dispatcher = app.is_a?(Routing::RouteSet::Dispatcher)
-
@constraints = constraints
@defaults = defaults
@required_defaults = nil
@@ -31,6 +23,7 @@ module ActionDispatch
@parts = nil
@decorated_ast = nil
@precedence = 0
+ @path_formatter = @path.build_formatter
end
def ast
@@ -72,15 +65,7 @@ module ActionDispatch
alias :segment_keys :parts
def format(path_options)
- path_options.delete_if do |key, value|
- value.to_s == defaults[key].to_s && !required_parts.include?(key)
- end
-
- Visitors::Formatter.new(path_options).accept(path.spec)
- end
-
- def optimized_path
- Visitors::OptimizedPath.new.accept(path.spec)
+ @path_formatter.evaluate path_options
end
def optional_parts
@@ -106,7 +91,7 @@ module ActionDispatch
end
def dispatcher?
- @dispatcher
+ @app.dispatcher?
end
def matches?(request)
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 36561c71a1..21817b374c 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -20,60 +20,32 @@ module ActionDispatch
# :nodoc:
VERSION = '2.0.0'
- class NullReq # :nodoc:
- attr_reader :env
- def initialize(env)
- @env = env
- end
-
- def request_method
- env['REQUEST_METHOD']
- end
-
- def path_info
- env['PATH_INFO']
- end
-
- def ip
- env['REMOTE_ADDR']
- end
-
- def [](k)
- env[k]
- end
- end
-
- attr_reader :request_class, :formatter
attr_accessor :routes
- def initialize(routes, options)
- @options = options
- @params_key = options[:parameters_key]
- @request_class = options[:request_class] || NullReq
- @routes = routes
+ def initialize(routes)
+ @routes = routes
end
- def call(env)
- env['PATH_INFO'] = Utils.normalize_path(env['PATH_INFO'])
-
- find_routes(env).each do |match, parameters, route|
- script_name, path_info, set_params = env.values_at('SCRIPT_NAME',
- 'PATH_INFO',
- @params_key)
+ def serve(req)
+ find_routes(req).each do |match, parameters, route|
+ set_params = req.path_parameters
+ path_info = req.path_info
+ script_name = req.script_name
unless route.path.anchored
- env['SCRIPT_NAME'] = (script_name.to_s + match.to_s).chomp('/')
- env['PATH_INFO'] = match.post_match
+ req.script_name = (script_name.to_s + match.to_s).chomp('/')
+ req.path_info = match.post_match
+ req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
end
- env[@params_key] = (set_params || {}).merge parameters
+ req.path_parameters = set_params.merge parameters
- status, headers, body = route.app.call(env)
+ status, headers, body = route.app.serve(req)
if 'pass' == headers['X-Cascade']
- env['SCRIPT_NAME'] = script_name
- env['PATH_INFO'] = path_info
- env[@params_key] = set_params
+ req.script_name = script_name
+ req.path_info = path_info
+ req.path_parameters = set_params
next
end
@@ -83,14 +55,14 @@ module ActionDispatch
return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
end
- def recognize(req)
- find_routes(req.env).each do |match, parameters, route|
+ def recognize(rails_req)
+ find_routes(rails_req).each do |match, parameters, route|
unless route.path.anchored
- req.env['SCRIPT_NAME'] = match.to_s
- req.env['PATH_INFO'] = match.post_match.sub(/^([^\/])/, '/\1')
+ rails_req.script_name = match.to_s
+ rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
end
- yield(route, nil, parameters)
+ yield(route, parameters)
end
end
@@ -124,29 +96,31 @@ module ActionDispatch
simulator.memos(path) { [] }
end
- def find_routes env
- req = request_class.new(env)
-
+ def find_routes req
routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
r.path.match(req.path_info)
}
- routes.concat get_routes_as_head(routes)
- routes.sort_by!(&:precedence).select! { |r| r.matches?(req) }
+ if req.env["REQUEST_METHOD"] === "HEAD"
+ routes.concat get_routes_as_head(routes)
+ end
+
+ routes.select! { |r| r.matches?(req) }
+ routes.sort_by!(&:precedence)
routes.map! { |r|
match_data = r.path.match(req.path_info)
- match_names = match_data.names.map { |n| n.to_sym }
- match_values = match_data.captures.map { |v| v && Utils.unescape_uri(v) }
- info = Hash[match_names.zip(match_values).find_all { |_, y| y }]
-
- [match_data, r.defaults.merge(info), r]
+ path_parameters = r.defaults.dup
+ match_data.names.zip(match_data.captures) { |name,val|
+ path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
+ }
+ [match_data, path_parameters, r]
}
end
def get_routes_as_head(routes)
precedence = (routes.map(&:precedence).max || 0) + 1
- routes = routes.select { |r|
+ routes.select { |r|
r.verb === "GET" && !(r.verb === "HEAD")
}.map! { |r|
Route.new(r.name,
@@ -157,8 +131,6 @@ module ActionDispatch
route.precedence = r.precedence + precedence
end
}
- routes.flatten!
- routes
end
end
end
diff --git a/actionpack/lib/action_dispatch/journey/router/strexp.rb b/actionpack/lib/action_dispatch/journey/router/strexp.rb
index f97f1a223e..4b7738f335 100644
--- a/actionpack/lib/action_dispatch/journey/router/strexp.rb
+++ b/actionpack/lib/action_dispatch/journey/router/strexp.rb
@@ -6,18 +6,21 @@ module ActionDispatch
alias :compile :new
end
- attr_reader :path, :requirements, :separators, :anchor
+ attr_reader :path, :requirements, :separators, :anchor, :ast
- def initialize(path, requirements, separators, anchor = true)
+ def self.build(path, requirements, separators, anchor = true)
+ parser = Journey::Parser.new
+ ast = parser.parse path
+ new ast, path, requirements, separators, anchor
+ end
+
+ def initialize(ast, path, requirements, separators, anchor = true)
+ @ast = ast
@path = path
@requirements = requirements
@separators = separators
@anchor = anchor
end
-
- def names
- @path.scan(/:\w+/).map { |s| s.tr(':', '') }
- end
end
end
end
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index d9f634623d..52b4c8b489 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -1,14 +1,57 @@
# encoding: utf-8
-require 'thread_safe'
-
module ActionDispatch
module Journey # :nodoc:
+ class Format
+ ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
+ ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
+
+ class Parameter < Struct.new(:name, :escaper)
+ def escape(value); escaper.call value; end
+ end
+
+ def self.required_path(symbol)
+ Parameter.new symbol, ESCAPE_PATH
+ end
+
+ def self.required_segment(symbol)
+ Parameter.new symbol, ESCAPE_SEGMENT
+ end
+
+ def initialize(parts)
+ @parts = parts
+ @children = []
+ @parameters = []
+
+ parts.each_with_index do |object,i|
+ case object
+ when Journey::Format
+ @children << i
+ when Parameter
+ @parameters << i
+ end
+ end
+ end
+
+ def evaluate(hash)
+ parts = @parts.dup
+
+ @parameters.each do |index|
+ param = parts[index]
+ value = hash[param.name]
+ return ''.freeze unless value
+ parts[index] = param.escape value
+ end
+
+ @children.each { |index| parts[index] = parts[index].evaluate(hash) }
+
+ parts.join
+ end
+ end
+
module Visitors # :nodoc:
class Visitor # :nodoc:
- DISPATCH_CACHE = ThreadSafe::Cache.new { |h,k|
- h[k] = :"visit_#{k}"
- }
+ DISPATCH_CACHE = {}
def accept(node)
visit(node)
@@ -38,11 +81,41 @@ module ActionDispatch
def visit_STAR(n); unary(n); end
def terminal(node); end
- %w{ LITERAL SYMBOL SLASH DOT }.each do |t|
- class_eval %{ def visit_#{t}(n); terminal(n); end }, __FILE__, __LINE__
+ def visit_LITERAL(n); terminal(n); end
+ def visit_SYMBOL(n); terminal(n); end
+ def visit_SLASH(n); terminal(n); end
+ def visit_DOT(n); terminal(n); end
+
+ private_instance_methods(false).each do |pim|
+ next unless pim =~ /^visit_(.*)$/
+ DISPATCH_CACHE[$1.to_sym] = pim
end
end
+ class FormatBuilder < Visitor # :nodoc:
+ def accept(node); Journey::Format.new(super); end
+ def terminal(node); [node.left]; end
+
+ def binary(node)
+ visit(node.left) + visit(node.right)
+ end
+
+ def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
+
+ def visit_STAR(n)
+ [Journey::Format.required_path(n.left.to_sym)]
+ end
+
+ def visit_SYMBOL(n)
+ symbol = n.to_sym
+ if symbol == :controller
+ [Journey::Format.required_path(symbol)]
+ else
+ [Journey::Format.required_segment(symbol)]
+ end
+ end
+ end
+
# Loop through the requirements AST
class Each < Visitor # :nodoc:
attr_reader :block
@@ -52,8 +125,8 @@ module ActionDispatch
end
def visit(node)
- super
block.call(node)
+ super
end
end
@@ -77,90 +150,6 @@ module ActionDispatch
end
end
- class OptimizedPath < Visitor # :nodoc:
- def accept(node)
- Array(visit(node))
- end
-
- private
-
- def visit_CAT(node)
- [visit(node.left), visit(node.right)].flatten
- end
-
- def visit_SYMBOL(node)
- node.left[1..-1].to_sym
- end
-
- def visit_STAR(node)
- visit(node.left)
- end
-
- def visit_GROUP(node)
- []
- end
-
- %w{ LITERAL SLASH DOT }.each do |t|
- class_eval %{ def visit_#{t}(n); n.left; end }, __FILE__, __LINE__
- end
- end
-
- # Used for formatting urls (url_for)
- class Formatter < Visitor # :nodoc:
- attr_reader :options
-
- def initialize(options)
- @options = options
- end
-
- private
- def escape_path(value)
- Router::Utils.escape_path(value)
- end
-
- def escape_segment(value)
- Router::Utils.escape_segment(value)
- end
-
- def visit(node, optional = false)
- case node.type
- when :LITERAL, :SLASH, :DOT
- node.left
- when :STAR
- visit_STAR(node.left)
- when :GROUP
- visit(node.left, true)
- when :CAT
- visit_CAT(node, optional)
- when :SYMBOL
- visit_SYMBOL(node, node.to_sym)
- end
- end
-
- def visit_CAT(node, optional)
- left = visit(node.left, optional)
- right = visit(node.right, optional)
-
- if optional && !(right && left)
- ""
- else
- [left, right].join
- end
- end
-
- def visit_STAR(node)
- if value = options[node.to_sym]
- escape_path(value)
- end
- end
-
- def visit_SYMBOL(node, name)
- if value = options[name]
- name == :controller ? escape_path(value) : escape_segment(value)
- end
- end
- end
-
class Dot < Visitor # :nodoc:
def initialize
@nodes = []
diff --git a/actionpack/lib/action_dispatch/journey/visualizer/index.html.erb b/actionpack/lib/action_dispatch/journey/visualizer/index.html.erb
index 6aff10956a..9b28a65200 100644
--- a/actionpack/lib/action_dispatch/journey/visualizer/index.html.erb
+++ b/actionpack/lib/action_dispatch/journey/visualizer/index.html.erb
@@ -2,13 +2,13 @@
<html>
<head>
<title><%= title %></title>
- <link rel="stylesheet" href="https://raw.github.com/gist/1706081/af944401f75ea20515a02ddb3fb43d23ecb8c662/reset.css" type="text/css">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" type="text/css">
<style>
<% stylesheets.each do |style| %>
<%= style %>
<% end %>
</style>
- <script src="https://raw.github.com/gist/1706081/df464722a05c3c2bec450b7b5c8240d9c31fa52d/d3.min.js" type="text/javascript"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min.js" type="text/javascript"></script>
</head>
<body>
<div id="wrapper">
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 4821d2a899..e90f8b9ce6 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -10,7 +10,7 @@ module ActionDispatch
end
end
- # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
+ # The flash provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
# action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
# then expose the flash to its template. Actually, that exposure is automatically done.
@@ -37,8 +37,11 @@ module ActionDispatch
# flash.alert = "You must be logged in"
# flash.notice = "Post successfully created"
#
- # This example just places a string in the flash, but you can put any object in there. And of course, you can put as
- # many as you like at a time too. Just remember: They'll be gone by the time the next action has been performed.
+ # This example places a string in the flash. And of course, you can put as many as you like at a time too. If you want to pass
+ # non-primitive types, you will have to handle that in your application. Example: To show messages with links, you will have to
+ # use sanitize helper.
+ #
+ # Just remember: They'll be gone by the time the next action has been performed.
#
# See docs on the FlashHash class for more details about the flash.
class Flash
diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
index cbb2d475b1..6c8944e067 100644
--- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
@@ -32,9 +32,8 @@ module ActionDispatch
end
def render_html(status)
- found = false
- path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
- path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
+ path = "#{public_path}/#{status}.#{I18n.locale}.html"
+ path = "#{public_path}/#{status}.html" unless (found = File.exist?(path))
if found || File.exist?(path)
render_format(status, 'text/html', File.read(path))
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index cbb066b092..6a79b4e859 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -11,7 +11,7 @@ module ActionDispatch
# Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2]
# requires. Some Rack servers simply drop preceding headers, and only report
# the value that was {given in the last header}[http://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers].
- # If you are behind multiple proxy servers (like Nginx to HAProxy to Unicorn)
+ # If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn)
# then you should test your Rack server to make sure your data is good.
#
# IF YOU DON'T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING.
@@ -118,7 +118,7 @@ module ActionDispatch
#
# REMOTE_ADDR will be correct if the request is made directly against the
# Ruby process, on e.g. Heroku. When the request is proxied by another
- # server like HAProxy or Nginx, the IP address that made the original
+ # server like HAProxy or NGINX, the IP address that made the original
# request will be put in an X-Forwarded-For header. If there are multiple
# proxies, that header may contain a list of IPs. Other proxy services
# set the Client-Ip header instead, so we check that too.
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 0864e7ef2a..ed25c67ae5 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -49,7 +49,7 @@ module ActionDispatch
# reasonably sure that your upgrade is otherwise complete. Additionally,
# you should take care to make sure you are not relying on the ability to
# decode signed cookies generated by your app in external applications or
- # Javascript before upgrading.
+ # JavaScript before upgrading.
#
# Note that changing the secret key will invalidate all existing sessions!
class CookieStore < Rack::Session::Abstract::ID
diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
index cce0d75af4..6ffa242da4 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
@@ -148,8 +148,8 @@
// On key press perform a search for matching paths
searchElem.onkeyup = function(e){
var userInput = searchElem.value,
- defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + sanitizePath(userInput) +'):</th></tr>',
- defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + userInput +'):</th></tr>',
+ defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + escape(sanitizePath(userInput)) +'):</th></tr>',
+ defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + escape(userInput) +'):</th></tr>',
noExactMatch = '<tr><th colspan="4">No Exact Matches Found</th></tr>',
noFuzzyMatch = '<tr><th colspan="4">No Fuzzy Matches Found</th></tr>';
diff --git a/actionpack/lib/action_dispatch/routing/endpoint.rb b/actionpack/lib/action_dispatch/routing/endpoint.rb
new file mode 100644
index 0000000000..88aa13c3e8
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/endpoint.rb
@@ -0,0 +1,10 @@
+module ActionDispatch
+ module Routing
+ class Endpoint # :nodoc:
+ def dispatcher?; false; end
+ def redirect?; false; end
+ def matches?(req); true; end
+ def app; self; end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 71a0c5e826..ea3b2f419d 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -5,22 +5,15 @@ module ActionDispatch
module Routing
class RouteWrapper < SimpleDelegator
def endpoint
- rack_app ? rack_app.inspect : "#{controller}##{action}"
+ app.dispatcher? ? "#{controller}##{action}" : rack_app.inspect
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
+ def rack_app
+ app.app
end
def verb
@@ -73,7 +66,7 @@ module ActionDispatch
end
def engine?
- rack_app && rack_app.respond_to?(:routes)
+ rack_app.respond_to?(:routes)
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 58c7f5330e..235a840682 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -6,6 +6,8 @@ require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
+require 'action_dispatch/routing/endpoint'
+require 'active_support/deprecation'
module ActionDispatch
module Routing
@@ -15,121 +17,189 @@ module ActionDispatch
:controller, :action, :path_names, :constraints,
:shallow, :blocks, :defaults, :options]
- class Constraints #:nodoc:
- def self.new(app, constraints, request = Rack::Request)
- if constraints.any?
- super(app, constraints, request)
- else
- app
+ class Constraints < Endpoint #:nodoc:
+ attr_reader :app, :constraints
+
+ def initialize(app, constraints, dispatcher_p)
+ # Unwrap Constraints objects. I don't actually think it's possible
+ # to pass a Constraints object to this constructor, but there were
+ # multiple places that kept testing children of this object. I
+ # *think* they were just being defensive, but I have no idea.
+ if app.is_a?(self.class)
+ constraints += app.constraints
+ app = app.app
end
- end
- attr_reader :app, :constraints
+ @dispatcher = dispatcher_p
- def initialize(app, constraints, request)
- @app, @constraints, @request = app, constraints, request
+ @app, @constraints, = app, constraints
end
- def matches?(env)
- req = @request.new(env)
+ def dispatcher?; @dispatcher; end
+ def matches?(req)
@constraints.all? do |constraint|
(constraint.respond_to?(:matches?) && constraint.matches?(req)) ||
(constraint.respond_to?(:call) && constraint.call(*constraint_args(constraint, req)))
end
- ensure
- req.reset_parameters
end
- def call(env)
- matches?(env) ? @app.call(env) : [ 404, {'X-Cascade' => 'pass'}, [] ]
+ def serve(req)
+ return [ 404, {'X-Cascade' => 'pass'}, [] ] unless matches?(req)
+
+ if dispatcher?
+ @app.serve req
+ else
+ @app.call req.env
+ end
end
private
def constraint_args(constraint, request)
- constraint.arity == 1 ? [request] : [request.symbolized_path_parameters, request]
+ constraint.arity == 1 ? [request] : [request.path_parameters, request]
end
end
class Mapping #:nodoc:
- IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix, :format]
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
- WILDCARD_PATH = %r{\*([^/\)]+)\)?$}
- attr_reader :scope, :path, :options, :requirements, :conditions, :defaults
+ attr_reader :requirements, :conditions, :defaults
+ attr_reader :to, :default_controller, :default_action, :as, :anchor
+
+ def self.build(scope, path, options)
+ options = scope[:options].merge(options) if scope[:options]
+
+ options.delete :only
+ options.delete :except
+ options.delete :shallow_path
+ options.delete :shallow_prefix
+ options.delete :shallow
- def initialize(set, scope, path, options)
- @set, @scope, @path, @options = set, scope, path, options
- @requirements, @conditions, @defaults = {}, {}, {}
+ defaults = (scope[:defaults] || {}).merge options.delete(:defaults) || {}
- normalize_options!
- normalize_path!
- normalize_requirements!
- normalize_conditions!
- normalize_defaults!
+ new scope, path, defaults, options
+ end
+
+ def initialize(scope, path, defaults, options)
+ @requirements, @conditions = {}, {}
+ @defaults = defaults
+
+ @to = options.delete :to
+ @default_controller = options.delete(:controller) || scope[:controller]
+ @default_action = options.delete(:action) || scope[:action]
+ @as = options.delete :as
+ @anchor = options.delete :anchor
+
+ formatted = options.delete :format
+ via = Array(options.delete(:via) { [] })
+ options_constraints = options.delete :constraints
+
+ path = normalize_path! path, formatted
+ ast = path_ast path
+ path_params = path_params ast
+
+ options = normalize_options!(options, formatted, path_params, ast, scope[:module])
+
+
+ split_constraints(path_params, scope[:constraints]) if scope[:constraints]
+ constraints = constraints(options, path_params)
+
+ split_constraints path_params, constraints
+
+ @blocks = blocks(options_constraints, scope[:blocks])
+
+ if options_constraints.is_a?(Hash)
+ split_constraints path_params, options_constraints
+ options_constraints.each do |key, default|
+ if URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
+ @defaults[key] ||= default
+ end
+ end
+ end
+
+ normalize_format!(formatted)
+
+ @conditions[:path_info] = path
+ @conditions[:parsed_path_info] = ast
+
+ add_request_method(via, @conditions)
+ normalize_defaults!(options)
end
def to_route
- [ app, conditions, requirements, defaults, options[:as], options[:anchor] ]
+ [ app(@blocks), conditions, requirements, defaults, as, anchor ]
end
private
- def normalize_path!
- raise ArgumentError, "path is required" if @path.blank?
- @path = Mapper.normalize_path(@path)
+ def normalize_path!(path, format)
+ path = Mapper.normalize_path(path)
- if required_format?
- @path = "#{@path}.:format"
- elsif optional_format?
- @path = "#{@path}(.:format)"
+ if format == true
+ "#{path}.:format"
+ elsif optional_format?(path, format)
+ "#{path}(.:format)"
+ else
+ path
end
end
- def required_format?
- options[:format] == true
- end
-
- def optional_format?
- options[:format] != false && !path.include?(':format') && !path.end_with?('/')
+ def optional_format?(path, format)
+ format != false && !path.include?(':format') && !path.end_with?('/')
end
- def normalize_options!
- @options.reverse_merge!(scope[:options]) if scope[:options]
- path_without_format = path.sub(/\(\.:format\)$/, '')
-
+ def normalize_options!(options, formatted, path_params, path_ast, modyoule)
# Add a constraint for wildcard route to make it non-greedy and match the
# optional format part of the route by default
- if path_without_format.match(WILDCARD_PATH) && @options[:format] != false
- @options[$1.to_sym] ||= /.+?/
+ if formatted != false
+ path_ast.grep(Journey::Nodes::Star) do |node|
+ options[node.name.to_sym] ||= /.+?/
+ end
end
- if path_without_format.match(':controller')
- raise ArgumentError, ":controller segment is not allowed within a namespace block" if scope[:module]
+ if path_params.include?(:controller)
+ raise ArgumentError, ":controller segment is not allowed within a namespace block" if modyoule
# Add a default constraint for :controller path segments that matches namespaced
# controllers with default routes like :controller/:action/:id(.:format), e.g:
# GET /admin/products/show/1
# => { controller: 'admin/products', action: 'show', id: '1' }
- @options[:controller] ||= /.+?/
+ options[:controller] ||= /.+?/
end
- @options.merge!(default_controller_and_action)
+ if to.respond_to? :call
+ options
+ else
+ to_endpoint = split_to to
+ controller = to_endpoint[0] || default_controller
+ action = to_endpoint[1] || default_action
+
+ controller = add_controller_module(controller, modyoule)
+
+ options.merge! check_controller_and_action(path_params, controller, action)
+ end
end
- def normalize_requirements!
- constraints.each do |key, requirement|
- next unless segment_keys.include?(key) || key == :controller
- verify_regexp_requirement(requirement) if requirement.is_a?(Regexp)
- @requirements[key] = requirement
+ def split_constraints(path_params, constraints)
+ constraints.each_pair do |key, requirement|
+ if path_params.include?(key) || key == :controller
+ verify_regexp_requirement(requirement) if requirement.is_a?(Regexp)
+ @requirements[key] = requirement
+ else
+ @conditions[key] = requirement
+ end
end
+ end
- if options[:format] == true
+ def normalize_format!(formatted)
+ if formatted == true
@requirements[:format] ||= /.+/
- elsif Regexp === options[:format]
- @requirements[:format] = options[:format]
- elsif String === options[:format]
- @requirements[:format] = Regexp.compile(options[:format])
+ elsif Regexp === formatted
+ @requirements[:format] = formatted
+ @defaults[:format] = nil
+ elsif String === formatted
+ @requirements[:format] = Regexp.compile(formatted)
+ @defaults[:format] = formatted
end
end
@@ -143,31 +213,12 @@ module ActionDispatch
end
end
- def normalize_defaults!
- @defaults.merge!(scope[:defaults]) if scope[:defaults]
- @defaults.merge!(options[:defaults]) if options[:defaults]
-
- options.each do |key, default|
- unless Regexp === default || IGNORE_OPTIONS.include?(key)
+ def normalize_defaults!(options)
+ options.each_pair do |key, default|
+ unless Regexp === default
@defaults[key] = default
end
end
-
- if options[:constraints].is_a?(Hash)
- options[:constraints].each do |key, default|
- if URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
- @defaults[key] ||= default
- end
- end
- elsif options[:constraints]
- verify_callable_constraint(options[:constraints])
- end
-
- if Regexp === options[:format]
- @defaults[:format] = nil
- elsif String === options[:format]
- @defaults[:format] = options[:format]
- end
end
def verify_callable_constraint(callable_constraint)
@@ -176,144 +227,129 @@ module ActionDispatch
end
end
- def normalize_conditions!
- @conditions[:path_info] = path
-
- constraints.each do |key, condition|
- unless segment_keys.include?(key) || key == :controller
- @conditions[key] = condition
- end
- end
-
- required_defaults = []
- options.each do |key, required_default|
- unless segment_keys.include?(key) || IGNORE_OPTIONS.include?(key) || Regexp === required_default
- required_defaults << key
- end
- end
- @conditions[:required_defaults] = required_defaults
+ def add_request_method(via, conditions)
+ return if via == [:all]
- via_all = options.delete(:via) if options[:via] == :all
-
- if !via_all && options[:via].blank?
+ if via.empty?
msg = "You should not use the `match` method in your router without specifying an HTTP method.\n" \
"If you want to expose your action to both GET and POST, add `via: [:get, :post]` option.\n" \
"If you want to expose your action to GET, use `get` in the router:\n" \
" Instead of: match \"controller#action\"\n" \
" Do: get \"controller#action\""
- raise msg
+ raise ArgumentError, msg
end
- if via = options[:via]
- @conditions[:request_method] = Array(via).map { |m| m.to_s.dasherize.upcase }
- end
+ conditions[:request_method] = via.map { |m| m.to_s.dasherize.upcase }
end
- def app
- Constraints.new(endpoint, blocks, @set.request_class)
- end
+ def app(blocks)
+ return to if Redirect === to
- def default_controller_and_action
if to.respond_to?(:call)
- { }
+ Constraints.new(to, blocks, false)
else
- if to.is_a?(String)
- controller, action = to.split('#')
- elsif to.is_a?(Symbol)
- action = to.to_s
- end
-
- controller ||= default_controller
- action ||= default_action
-
- if @scope[:module] && !controller.is_a?(Regexp)
- if controller =~ %r{\A/}
- controller = controller[1..-1]
- else
- controller = [@scope[:module], controller].compact.join("/").presence
- end
- end
-
- if controller.is_a?(String) && controller =~ %r{\A/}
- raise ArgumentError, "controller name should not start with a slash"
+ if blocks.any?
+ Constraints.new(dispatcher, blocks, true)
+ else
+ dispatcher
end
+ end
+ end
- controller = controller.to_s unless controller.is_a?(Regexp)
- action = action.to_s unless action.is_a?(Regexp)
+ def check_controller_and_action(path_params, controller, action)
+ hash = check_part(:controller, controller, path_params, {}) do |part|
+ translate_controller(part) {
+ message = "'#{part}' is not a supported controller name. This can lead to potential routing problems."
+ message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use"
- if controller.blank? && segment_keys.exclude?(:controller)
- message = "Missing :controller key on routes definition, please check your routes."
raise ArgumentError, message
- end
+ }
+ end
- if action.blank? && segment_keys.exclude?(:action)
- message = "Missing :action key on routes definition, please check your routes."
- raise ArgumentError, message
- end
+ check_part(:action, action, path_params, hash) { |part|
+ part.is_a?(Regexp) ? part : part.to_s
+ }
+ end
- if controller.is_a?(String) && controller !~ /\A[a-z_0-9\/]*\z/
- message = "'#{controller}' is not a supported controller name. This can lead to potential routing problems."
- message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use"
+ def check_part(name, part, path_params, hash)
+ if part
+ hash[name] = yield(part)
+ else
+ unless path_params.include?(name)
+ message = "Missing :#{name} key on routes definition, please check your routes."
raise ArgumentError, message
end
-
- hash = {}
- hash[:controller] = controller unless controller.blank?
- hash[:action] = action unless action.blank?
- hash
end
- end
-
- def blocks
- if options[:constraints].present? && !options[:constraints].is_a?(Hash)
- [options[:constraints]]
+ hash
+ end
+
+ def split_to(to)
+ case to
+ when Symbol
+ ActiveSupport::Deprecation.warn "defining a route where `to` is a symbol is deprecated. Please change \"to: :#{to}\" to \"action: :#{to}\""
+ [nil, to.to_s]
+ when /#/ then to.split('#')
+ when String
+ ActiveSupport::Deprecation.warn "defining a route where `to` is a controller without an action is deprecated. Please change \"to: :#{to}\" to \"controller: :#{to}\""
+ [to, nil]
else
- scope[:blocks] || []
+ []
end
end
- def constraints
- @constraints ||= {}.tap do |constraints|
- constraints.merge!(scope[:constraints]) if scope[:constraints]
-
- options.except(*IGNORE_OPTIONS).each do |key, option|
- constraints[key] = option if Regexp === option
+ def add_controller_module(controller, modyoule)
+ if modyoule && !controller.is_a?(Regexp)
+ if controller =~ %r{\A/}
+ controller[1..-1]
+ else
+ [modyoule, controller].compact.join("/")
end
-
- constraints.merge!(options[:constraints]) if options[:constraints].is_a?(Hash)
+ else
+ controller
end
end
- def segment_keys
- @segment_keys ||= path_pattern.names.map{ |s| s.to_sym }
- end
+ def translate_controller(controller)
+ return controller if Regexp === controller
+ return controller.to_s if controller =~ /\A[a-z_0-9][a-z_0-9\/]*\z/
- def path_pattern
- Journey::Path::Pattern.new(strexp)
- end
-
- def strexp
- Journey::Router::Strexp.compile(path, requirements, SEPARATORS)
+ yield
end
- def endpoint
- to.respond_to?(:call) ? to : dispatcher
+ def blocks(options_constraints, scope_blocks)
+ if options_constraints && !options_constraints.is_a?(Hash)
+ verify_callable_constraint(options_constraints)
+ [options_constraints]
+ else
+ scope_blocks || []
+ end
end
- def dispatcher
- Routing::RouteSet::Dispatcher.new(:defaults => defaults)
+ def constraints(options, path_params)
+ constraints = {}
+ required_defaults = []
+ options.each_pair do |key, option|
+ if Regexp === option
+ constraints[key] = option
+ else
+ required_defaults << key unless path_params.include?(key)
+ end
+ end
+ @conditions[:required_defaults] = required_defaults
+ constraints
end
- def to
- options[:to]
+ def path_params(ast)
+ ast.grep(Journey::Nodes::Symbol).map { |n| n.name.to_sym }
end
- def default_controller
- options[:controller] || scope[:controller]
+ def path_ast(path)
+ parser = Journey::Parser.new
+ parser.parse path
end
- def default_action
- options[:action] || scope[:action]
+ def dispatcher
+ Routing::RouteSet::Dispatcher.new(defaults)
end
end
@@ -415,6 +451,12 @@ module ActionDispatch
# [:action]
# The route's action.
#
+ # [:param]
+ # Overrides the default resource identifier `:id` (name of the
+ # dynamic segment used to generate the routes).
+ # You can access that segment from your controller using
+ # <tt>params[<:param>]</tt>.
+ #
# [:path]
# The path prefix for the routes.
#
@@ -675,7 +717,7 @@ module ActionDispatch
# resources :posts, module: "admin"
#
# If you want to route /admin/posts to +PostsController+
- # (without the Admin:: module prefix), you could use
+ # (without the <tt>Admin::</tt> module prefix), you could use
#
# scope "/admin" do
# resources :posts
@@ -1392,7 +1434,7 @@ module ActionDispatch
end
with_scope_level(:nested) do
- if shallow? && shallow_nesting_depth > 1
+ if shallow? && shallow_nesting_depth >= 1
shallow_scope(parent_resource.nested_scope, nested_options) { yield }
else
scope(parent_resource.nested_scope, nested_options) { yield }
@@ -1426,7 +1468,20 @@ module ActionDispatch
if rest.empty? && Hash === path
options = path
path, to = options.find { |name, _value| name.is_a?(String) }
- options[:to] = to
+
+ case to
+ when Symbol
+ options[:action] = to
+ when String
+ if to =~ /#/
+ options[:to] = to
+ else
+ options[:controller] = to
+ end
+ else
+ options[:to] = to
+ end
+
options.delete(path)
paths = [path]
else
@@ -1480,6 +1535,8 @@ module ActionDispatch
def add_route(action, options) # :nodoc:
path = path_for_action(action, options.delete(:path))
+ raise ArgumentError, "path is required" if path.blank?
+
action = action.to_s.dup
if action =~ /^[\w\-\/]+$/
@@ -1494,7 +1551,7 @@ module ActionDispatch
options[:as] = name_for_action(options[:as], action)
end
- mapping = Mapping.new(@set, @scope, URI.parser.escape(path), options)
+ mapping = Mapping.build(@scope, URI.parser.escape(path), options)
app, conditions, requirements, defaults, as, anchor = mapping.to_route
@set.add_route(app, conditions, requirements, defaults, as, anchor)
end
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index b08e62543b..3c1c4fadf6 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -3,10 +3,11 @@ require 'active_support/core_ext/uri'
require 'active_support/core_ext/array/extract_options'
require 'rack/utils'
require 'action_controller/metal/exceptions'
+require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
- class Redirect # :nodoc:
+ class Redirect < Endpoint # :nodoc:
attr_reader :status, :block
def initialize(status, block)
@@ -14,18 +15,15 @@ module ActionDispatch
@block = block
end
- def call(env)
- req = Request.new(env)
+ def redirect?; true; end
- # If any of the path parameters has an invalid encoding then
- # raise since it's likely to trigger errors further on.
- req.symbolized_path_parameters.each do |key, value|
- unless value.valid_encoding?
- raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
- end
- end
+ def call(env)
+ serve Request.new env
+ end
- uri = URI.parse(path(req.symbolized_path_parameters, req))
+ def serve(req)
+ req.check_path_parameters!
+ uri = URI.parse(path(req.path_parameters, req))
unless uri.host
if relative_path?(uri.path)
@@ -39,7 +37,7 @@ module ActionDispatch
uri.host ||= req.host
uri.port ||= req.port unless req.standard_port?
- body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
+ body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>)
headers = {
'Location' => uri.to_s,
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index e699419f23..69535faabd 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -8,6 +8,7 @@ require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
require 'action_controller/metal/exceptions'
require 'action_dispatch/http/request'
+require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
@@ -18,27 +19,17 @@ module ActionDispatch
# alias inspect to to_s.
alias inspect to_s
- PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
-
- class Dispatcher #:nodoc:
- def initialize(options={})
- @defaults = options[:defaults]
- @glob_param = options.delete(:glob)
+ class Dispatcher < Routing::Endpoint #:nodoc:
+ def initialize(defaults)
+ @defaults = defaults
@controller_class_names = ThreadSafe::Cache.new
end
- def call(env)
- params = env[PARAMETERS_KEY]
+ def dispatcher?; true; end
- # If any of the path parameters has an invalid encoding then
- # raise since it's likely to trigger errors further on.
- params.each do |key, value|
- next unless value.respond_to?(:valid_encoding?)
-
- unless value.valid_encoding?
- raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
- end
- end
+ def serve(req)
+ req.check_path_parameters!
+ params = req.path_parameters
prepare_params!(params)
@@ -47,13 +38,12 @@ module ActionDispatch
return [404, {'X-Cascade' => 'pass'}, []]
end
- dispatch(controller, params[:action], env)
+ dispatch(controller, params[:action], req.env)
end
def prepare_params!(params)
normalize_controller!(params)
merge_default_action!(params)
- split_glob_param!(params) if @glob_param
end
# If this is a default_controller (i.e. a controller specified by the user)
@@ -89,10 +79,6 @@ module ActionDispatch
def merge_default_action!(params)
params[:action] ||= 'index'
end
-
- def split_glob_param!(params)
- params[@glob_param] = params[@glob_param].split('/').map { |v| URI.parser.unescape(v) }
- end
end
# A NamedRouteCollection instance is a collection of named routes, and also
@@ -165,10 +151,8 @@ module ActionDispatch
def initialize(route, options)
super
- @klass = Journey::Router::Utils
@required_parts = @route.required_parts
@arg_size = @required_parts.size
- @optimized_path = @route.optimized_path
end
def call(t, args)
@@ -184,18 +168,14 @@ module ActionDispatch
private
def optimized_helper(args)
- params = Hash[parameterize_args(args)]
+ params = parameterize_args(args)
missing_keys = missing_keys(params)
unless missing_keys.empty?
raise_generation_error(params, missing_keys)
end
- @optimized_path.map{ |segment| replace_segment(params, segment) }.join
- end
-
- def replace_segment(params, segment)
- Symbol === segment ? @klass.escape_segment(params[segment]) : segment
+ @route.format params
end
def optimize_routes_generation?(t)
@@ -203,7 +183,9 @@ module ActionDispatch
end
def parameterize_args(args)
- @required_parts.zip(args.map(&:to_param))
+ params = {}
+ @required_parts.zip(args.map(&:to_param)) { |k,v| params[k] = v }
+ params
end
def missing_keys(args)
@@ -226,21 +208,23 @@ module ActionDispatch
end
def call(t, args)
- options = t.url_options.merge @options
- hash = handle_positional_args(t, args, options, @segment_keys)
+ controller_options = t.url_options
+ options = controller_options.merge @options
+ hash = handle_positional_args(controller_options, args, options, @segment_keys)
t._routes.url_for(hash)
end
- def handle_positional_args(t, args, result, keys)
+ def handle_positional_args(controller_options, args, result, path_params)
inner_options = args.extract_options!
if args.size > 0
- if args.size < keys.size - 1 # take format into account
- keys -= t.url_options.keys
- keys -= result.keys
+ if args.size < path_params.size - 1 # take format into account
+ path_params -= controller_options.keys
+ path_params -= result.keys
end
- keys -= inner_options.keys
- result.merge!(Hash[keys.zip(args)])
+ path_params.each { |param|
+ result[param] = inner_options[param] || args.shift
+ }
end
result.merge!(inner_options)
@@ -304,9 +288,7 @@ module ActionDispatch
@finalized = false
@set = Journey::Routes.new
- @router = Journey::Router.new(@set, {
- :parameters_key => PARAMETERS_KEY,
- :request_class => request_class})
+ @router = Journey::Router.new @set
@formatter = Journey::Formatter.new @set
end
@@ -436,7 +418,9 @@ module ActionDispatch
"http://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
end
- path = build_path(conditions.delete(:path_info), requirements, SEPARATORS, anchor)
+ path = conditions.delete :path_info
+ ast = conditions.delete :parsed_path_info
+ path = build_path(path, ast, requirements, anchor)
conditions = build_conditions(conditions, path.names.map { |x| x.to_sym })
route = @set.add_route(app, path, conditions, defaults, name)
@@ -444,8 +428,9 @@ module ActionDispatch
route
end
- def build_path(path, requirements, separators, anchor)
+ def build_path(path, ast, requirements, anchor)
strexp = Journey::Router::Strexp.new(
+ ast,
path,
requirements,
SEPARATORS,
@@ -598,7 +583,7 @@ module ActionDispatch
# Generates a path from routes, returns [path, params].
# If no route is generated the formatter will raise ActionController::UrlGenerationError
def generate
- @set.formatter.generate(:path_info, named_route, options, recall, PARAMETERIZE)
+ @set.formatter.generate(named_route, options, recall, PARAMETERIZE)
end
def different_controller?
@@ -671,19 +656,24 @@ module ActionDispatch
RESERVED_OPTIONS.each { |ro| path_options.delete ro }
path, params = generate(path_options, recall)
- params.merge!(options[:params] || {})
-
- ActionDispatch::Http::URL.url_for(options.merge!({
- :path => path,
- :script_name => script_name,
- :params => params,
- :user => user,
- :password => password
- }))
+
+ if options.key? :params
+ params.merge! options[:params]
+ end
+
+ options[:path] = path
+ options[:script_name] = script_name
+ options[:params] = params
+ options[:user] = user
+ options[:password] = password
+
+ ActionDispatch::Http::URL.url_for(options)
end
def call(env)
- @router.call(env)
+ req = request_class.new(env)
+ req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
+ @router.serve(req)
end
def recognize_path(path, environment = {})
@@ -697,8 +687,8 @@ module ActionDispatch
raise ActionController::RoutingError, e.message
end
- req = @request_class.new(env)
- @router.recognize(req) do |route, _matches, params|
+ req = request_class.new(env)
+ @router.recognize(req) do |route, params|
params.merge!(extras)
params.each do |key, value|
if value.is_a?(String)
@@ -706,14 +696,12 @@ module ActionDispatch
params[key] = URI.parser.unescape(value)
end
end
- old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
- env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
- dispatcher = route.app
- while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
- dispatcher = dispatcher.app
- end
+ old_params = req.path_parameters
+ req.path_parameters = old_params.merge params
+ app = route.app
+ if app.matches?(req) && app.dispatcher?
+ dispatcher = app.app
- if dispatcher.is_a?(Dispatcher)
if dispatcher.controller(params, false)
dispatcher.prepare_params!(params)
return params
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index cc6b763093..08d4eee7fb 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -3,7 +3,6 @@ require 'uri'
require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/object/try'
require 'rack/test'
-require 'minitest'
module ActionDispatch
module Integration #:nodoc:
@@ -189,8 +188,8 @@ module ActionDispatch
# This makes app.url_for and app.foo_path available in the console
if app.respond_to?(:routes)
singleton_class.class_eval do
- include app.routes.url_helpers if app.routes.respond_to?(:url_helpers)
- include app.routes.mounted_helpers if app.routes.respond_to?(:mounted_helpers)
+ include app.routes.url_helpers
+ include app.routes.mounted_helpers
end
end
@@ -270,12 +269,6 @@ module ActionDispatch
path = location.query ? "#{location.path}?#{location.query}" : location.path
end
- unless ActionController::Base < ActionController::Testing
- ActionController::Base.class_eval do
- include ActionController::Testing
- end
- end
-
hostname, port = host.split(':')
env = {
@@ -300,13 +293,7 @@ module ActionDispatch
# NOTE: rack-test v0.5 doesn't build a default uri correctly
# Make sure requested path is always a full uri
- uri = URI.parse('/')
- uri.scheme ||= env['rack.url_scheme']
- uri.host ||= env['SERVER_NAME']
- uri.port ||= env['SERVER_PORT'].try(:to_i)
- uri += path
-
- session.request(uri.to_s, env)
+ session.request(build_full_uri(path, env), env)
@request_count += 1
@request = ActionDispatch::Request.new(session.last_request.env)
@@ -319,6 +306,10 @@ module ActionDispatch
return response.status
end
+
+ def build_full_uri(path, env)
+ "#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
+ end
end
module Runner
@@ -356,7 +347,7 @@ module ActionDispatch
# By default, a single session is automatically created for you, but you
# can use this method to open multiple sessions that ought to be tested
# simultaneously.
- def open_session(app = nil)
+ def open_session
dup.tap do |session|
yield session if block_given?
end
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index 57c678843b..de3dc5f924 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -39,7 +39,7 @@ module ActionDispatch
end
def action=(action_name)
- path_parameters["action"] = action_name.to_s
+ path_parameters[:action] = action_name.to_s
end
def if_modified_since=(last_modified)
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 46de36317e..6584d20840 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -251,7 +251,6 @@ end
module ActionController
class Base
- include ActionController::Testing
# This stub emulates the Railtie including the URL helpers from a Rails application
include SharedTestRoutes.url_helpers
include SharedTestRoutes.mounted_helpers
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index 580604df3a..f07d201563 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -56,13 +56,16 @@ class AssertSelectTest < ActionController::TestCase
def setup
super
+ @old_delivery_method = ActionMailer::Base.delivery_method
+ @old_perform_deliveries = ActionMailer::Base.perform_deliveries
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
- ActionMailer::Base.deliveries = []
end
def teardown
super
+ ActionMailer::Base.delivery_method = @old_delivery_method
+ ActionMailer::Base.perform_deliveries = @old_perform_deliveries
ActionMailer::Base.deliveries.clear
end
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index 03d5d27cf4..89667df3a4 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -68,12 +68,11 @@ class ContentTypeTest < ActionController::TestCase
end
def test_render_changed_charset_default
- ActionDispatch::Response.default_charset = "utf-16"
- get :render_defaults
- assert_equal "utf-16", @response.charset
- assert_equal Mime::HTML, @response.content_type
- ensure
- ActionDispatch::Response.default_charset = "utf-8"
+ with_default_charset "utf-16" do
+ get :render_defaults
+ assert_equal "utf-16", @response.charset
+ assert_equal Mime::HTML, @response.content_type
+ end
end
# :ported:
@@ -105,12 +104,11 @@ class ContentTypeTest < ActionController::TestCase
end
def test_nil_default_for_erb
- ActionDispatch::Response.default_charset = nil
- get :render_default_for_erb
- assert_equal Mime::HTML, @response.content_type
- assert_nil @response.charset, @response.headers.inspect
- ensure
- ActionDispatch::Response.default_charset = "utf-8"
+ with_default_charset nil do
+ get :render_default_for_erb
+ assert_equal Mime::HTML, @response.content_type
+ assert_nil @response.charset, @response.headers.inspect
+ end
end
def test_default_for_erb
@@ -130,6 +128,16 @@ class ContentTypeTest < ActionController::TestCase
assert_equal Mime::HTML, @response.content_type
assert_equal "utf-8", @response.charset
end
+
+ private
+
+ def with_default_charset(charset)
+ old_default_charset = ActionDispatch::Response.default_charset
+ ActionDispatch::Response.default_charset = charset
+ yield
+ ensure
+ ActionDispatch::Response.default_charset = old_default_charset
+ end
end
class AcceptBasedContentTypeTest < ActionController::TestCase
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index c87494aa64..b2b01b3fa9 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -2,13 +2,13 @@ require 'abstract_unit'
class ActionController::Base
class << self
- %w(append_around_filter prepend_after_filter prepend_around_filter prepend_before_filter skip_after_filter skip_before_filter skip_filter).each do |pending|
+ %w(append_around_action prepend_after_action prepend_around_action prepend_before_action skip_after_action skip_before_action skip_action_callback).each do |pending|
define_method(pending) do |*args|
$stderr.puts "#{pending} unimplemented: #{args.inspect}"
end unless method_defined?(pending)
end
- def before_filters
+ def before_actions
filters = _process_action_callbacks.select { |c| c.kind == :before }
filters.map! { |c| c.raw_filter }
end
@@ -28,8 +28,8 @@ end
class FilterTest < ActionController::TestCase
class TestController < ActionController::Base
- before_filter :ensure_login
- after_filter :clean_up
+ before_action :ensure_login
+ after_action :clean_up
def show
render :inline => "ran action"
@@ -42,13 +42,13 @@ class FilterTest < ActionController::TestCase
end
def clean_up
- @ran_after_filter ||= []
- @ran_after_filter << "clean_up"
+ @ran_after_action ||= []
+ @ran_after_action << "clean_up"
end
end
class ChangingTheRequirementsController < TestController
- before_filter :ensure_login, :except => [:go_wild]
+ before_action :ensure_login, :except => [:go_wild]
def go_wild
render :text => "gobble"
@@ -56,9 +56,9 @@ class FilterTest < ActionController::TestCase
end
class TestMultipleFiltersController < ActionController::Base
- before_filter :try_1
- before_filter :try_2
- before_filter :try_3
+ before_action :try_1
+ before_action :try_2
+ before_action :try_3
(1..3).each do |i|
define_method "fail_#{i}" do
@@ -78,8 +78,8 @@ class FilterTest < ActionController::TestCase
end
class RenderingController < ActionController::Base
- before_filter :before_filter_rendering
- after_filter :unreached_after_filter
+ before_action :before_action_rendering
+ after_action :unreached_after_action
def show
@ran_action = true
@@ -87,29 +87,29 @@ class FilterTest < ActionController::TestCase
end
private
- def before_filter_rendering
+ def before_action_rendering
@ran_filter ||= []
- @ran_filter << "before_filter_rendering"
+ @ran_filter << "before_action_rendering"
render :inline => "something else"
end
- def unreached_after_filter
- @ran_filter << "unreached_after_filter_after_render"
+ def unreached_after_action
+ @ran_filter << "unreached_after_action_after_render"
end
end
- class RenderingForPrependAfterFilterController < RenderingController
- prepend_after_filter :unreached_prepend_after_filter
+ class RenderingForPrependAfterActionController < RenderingController
+ prepend_after_action :unreached_prepend_after_action
private
- def unreached_prepend_after_filter
- @ran_filter << "unreached_preprend_after_filter_after_render"
+ def unreached_prepend_after_action
+ @ran_filter << "unreached_preprend_after_action_after_render"
end
end
- class BeforeFilterRedirectionController < ActionController::Base
- before_filter :before_filter_redirects
- after_filter :unreached_after_filter
+ class BeforeActionRedirectionController < ActionController::Base
+ before_action :before_action_redirects
+ after_action :unreached_after_action
def show
@ran_action = true
@@ -122,23 +122,23 @@ class FilterTest < ActionController::TestCase
end
private
- def before_filter_redirects
+ def before_action_redirects
@ran_filter ||= []
- @ran_filter << "before_filter_redirects"
+ @ran_filter << "before_action_redirects"
redirect_to(:action => 'target_of_redirection')
end
- def unreached_after_filter
- @ran_filter << "unreached_after_filter_after_redirection"
+ def unreached_after_action
+ @ran_filter << "unreached_after_action_after_redirection"
end
end
- class BeforeFilterRedirectionForPrependAfterFilterController < BeforeFilterRedirectionController
- prepend_after_filter :unreached_prepend_after_filter_after_redirection
+ class BeforeActionRedirectionForPrependAfterActionController < BeforeActionRedirectionController
+ prepend_after_action :unreached_prepend_after_action_after_redirection
private
- def unreached_prepend_after_filter_after_redirection
- @ran_filter << "unreached_prepend_after_filter_after_redirection"
+ def unreached_prepend_after_action_after_redirection
+ @ran_filter << "unreached_prepend_after_action_after_redirection"
end
end
@@ -151,8 +151,8 @@ class FilterTest < ActionController::TestCase
render :inline => "ran action"
end
- def show_without_filter
- render :inline => "ran action without filter"
+ def show_without_action
+ render :inline => "ran action without action"
end
private
@@ -168,70 +168,70 @@ class FilterTest < ActionController::TestCase
end
class ConditionalCollectionFilterController < ConditionalFilterController
- before_filter :ensure_login, :except => [ :show_without_filter, :another_action ]
+ before_action :ensure_login, :except => [ :show_without_action, :another_action ]
end
class OnlyConditionSymController < ConditionalFilterController
- before_filter :ensure_login, :only => :show
+ before_action :ensure_login, :only => :show
end
class ExceptConditionSymController < ConditionalFilterController
- before_filter :ensure_login, :except => :show_without_filter
+ before_action :ensure_login, :except => :show_without_action
end
class BeforeAndAfterConditionController < ConditionalFilterController
- before_filter :ensure_login, :only => :show
- after_filter :clean_up_tmp, :only => :show
+ before_action :ensure_login, :only => :show
+ after_action :clean_up_tmp, :only => :show
end
class OnlyConditionProcController < ConditionalFilterController
- before_filter(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
+ before_action(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_action", true) }
end
class ExceptConditionProcController < ConditionalFilterController
- before_filter(:except => :show_without_filter) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
+ before_action(:except => :show_without_action) {|c| c.instance_variable_set(:"@ran_proc_action", true) }
end
class ConditionalClassFilter
- def self.before(controller) controller.instance_variable_set(:"@ran_class_filter", true) end
+ def self.before(controller) controller.instance_variable_set(:"@ran_class_action", true) end
end
class OnlyConditionClassController < ConditionalFilterController
- before_filter ConditionalClassFilter, :only => :show
+ before_action ConditionalClassFilter, :only => :show
end
class ExceptConditionClassController < ConditionalFilterController
- before_filter ConditionalClassFilter, :except => :show_without_filter
+ before_action ConditionalClassFilter, :except => :show_without_action
end
class AnomolousYetValidConditionController < ConditionalFilterController
- before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_filter1", true)}, :except => :show_without_filter) { |c| c.instance_variable_set(:"@ran_proc_filter2", true)}
+ before_action(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_action1", true)}, :except => :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action2", true)}
end
class OnlyConditionalOptionsFilter < ConditionalFilterController
- before_filter :ensure_login, :only => :index, :if => Proc.new {|c| c.instance_variable_set(:"@ran_conditional_index_proc", true) }
+ before_action :ensure_login, :only => :index, :if => Proc.new {|c| c.instance_variable_set(:"@ran_conditional_index_proc", true) }
end
class ConditionalOptionsFilter < ConditionalFilterController
- before_filter :ensure_login, :if => Proc.new { |c| true }
- before_filter :clean_up_tmp, :if => Proc.new { |c| false }
+ before_action :ensure_login, :if => Proc.new { |c| true }
+ before_action :clean_up_tmp, :if => Proc.new { |c| false }
end
class ConditionalOptionsSkipFilter < ConditionalFilterController
- before_filter :ensure_login
- before_filter :clean_up_tmp
+ before_action :ensure_login
+ before_action :clean_up_tmp
- skip_before_filter :ensure_login, if: -> { false }
- skip_before_filter :clean_up_tmp, if: -> { true }
+ skip_before_action :ensure_login, if: -> { false }
+ skip_before_action :clean_up_tmp, if: -> { true }
end
class ClassController < ConditionalFilterController
- before_filter ConditionalClassFilter
+ before_action ConditionalClassFilter
end
class PrependingController < TestController
- prepend_before_filter :wonderful_life
- # skip_before_filter :fire_flash
+ prepend_before_action :wonderful_life
+ # skip_before_action :fire_flash
private
def wonderful_life
@@ -241,8 +241,8 @@ class FilterTest < ActionController::TestCase
end
class SkippingAndLimitedController < TestController
- skip_before_filter :ensure_login
- before_filter :ensure_login, :only => :index
+ skip_before_action :ensure_login
+ before_action :ensure_login, :only => :index
def index
render :text => 'ok'
@@ -254,9 +254,9 @@ class FilterTest < ActionController::TestCase
end
class SkippingAndReorderingController < TestController
- skip_before_filter :ensure_login
- before_filter :find_record
- before_filter :ensure_login
+ skip_before_action :ensure_login
+ before_action :find_record
+ before_action :ensure_login
def index
render :text => 'ok'
@@ -270,10 +270,10 @@ class FilterTest < ActionController::TestCase
end
class ConditionalSkippingController < TestController
- skip_before_filter :ensure_login, :only => [ :login ]
- skip_after_filter :clean_up, :only => [ :login ]
+ skip_before_action :ensure_login, :only => [ :login ]
+ skip_after_action :clean_up, :only => [ :login ]
- before_filter :find_user, :only => [ :change_password ]
+ before_action :find_user, :only => [ :change_password ]
def login
render :inline => "ran action"
@@ -291,8 +291,8 @@ class FilterTest < ActionController::TestCase
end
class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
- before_filter :conditional_in_parent_before, :only => [:show, :another_action]
- after_filter :conditional_in_parent_after, :only => [:show, :another_action]
+ before_action :conditional_in_parent_before, :only => [:show, :another_action]
+ after_action :conditional_in_parent_after, :only => [:show, :another_action]
private
@@ -308,20 +308,20 @@ class FilterTest < ActionController::TestCase
end
class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
- skip_before_filter :conditional_in_parent_before, :only => :another_action
- skip_after_filter :conditional_in_parent_after, :only => :another_action
+ skip_before_action :conditional_in_parent_before, :only => :another_action
+ skip_after_action :conditional_in_parent_after, :only => :another_action
end
class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
- skip_before_filter :conditional_in_parent_before, :only => :show
+ skip_before_action :conditional_in_parent_before, :only => :show
end
class ProcController < PrependingController
- before_filter(proc { |c| c.instance_variable_set(:"@ran_proc_filter", true) })
+ before_action(proc { |c| c.instance_variable_set(:"@ran_proc_action", true) })
end
class ImplicitProcController < PrependingController
- before_filter { |c| c.instance_variable_set(:"@ran_proc_filter", true) }
+ before_action { |c| c.instance_variable_set(:"@ran_proc_action", true) }
end
class AuditFilter
@@ -367,7 +367,7 @@ class FilterTest < ActionController::TestCase
end
class AuditController < ActionController::Base
- before_filter(AuditFilter)
+ before_action(AuditFilter)
def show
render :text => "hello"
@@ -375,14 +375,14 @@ class FilterTest < ActionController::TestCase
end
class AroundFilterController < PrependingController
- around_filter AroundFilter.new
+ around_action AroundFilter.new
end
class BeforeAfterClassFilterController < PrependingController
begin
filter = AroundFilter.new
- before_filter filter
- after_filter filter
+ before_action filter
+ after_action filter
end
end
@@ -394,18 +394,18 @@ class FilterTest < ActionController::TestCase
super()
end
- before_filter { |c| c.class.execution_log << " before procfilter " }
- prepend_around_filter AroundFilter.new
+ before_action { |c| c.class.execution_log << " before procfilter " }
+ prepend_around_action AroundFilter.new
- after_filter { |c| c.class.execution_log << " after procfilter " }
- append_around_filter AppendedAroundFilter.new
+ after_action { |c| c.class.execution_log << " after procfilter " }
+ append_around_action AppendedAroundFilter.new
end
class MixedSpecializationController < ActionController::Base
class OutOfOrder < StandardError; end
- before_filter :first
- before_filter :second, :only => :foo
+ before_action :first
+ before_action :second, :only => :foo
def foo
render :text => 'foo'
@@ -426,7 +426,7 @@ class FilterTest < ActionController::TestCase
end
class DynamicDispatchController < ActionController::Base
- before_filter :choose
+ before_action :choose
%w(foo bar baz).each do |action|
define_method(action) { render :text => action }
@@ -439,9 +439,9 @@ class FilterTest < ActionController::TestCase
end
class PrependingBeforeAndAfterController < ActionController::Base
- prepend_before_filter :before_all
- prepend_after_filter :after_all
- before_filter :between_before_all_and_after_all
+ prepend_before_action :before_all
+ prepend_after_action :after_all
+ before_action :between_before_all_and_after_all
def before_all
@ran_filter ||= []
@@ -473,7 +473,7 @@ class FilterTest < ActionController::TestCase
end
class RescuedController < ActionController::Base
- around_filter RescuingAroundFilterWithBlock.new
+ around_action RescuingAroundFilterWithBlock.new
def show
raise ErrorToRescue.new("Something made the bad noise.")
@@ -482,10 +482,10 @@ class FilterTest < ActionController::TestCase
class NonYieldingAroundFilterController < ActionController::Base
- before_filter :filter_one
- around_filter :non_yielding_filter
- before_filter :filter_two
- after_filter :filter_three
+ before_action :filter_one
+ around_action :non_yielding_action
+ before_action :action_two
+ after_action :action_three
def index
render :inline => "index"
@@ -498,24 +498,24 @@ class FilterTest < ActionController::TestCase
@filters << "filter_one"
end
- def filter_two
- @filters << "filter_two"
+ def action_two
+ @filters << "action_two"
end
- def non_yielding_filter
+ def non_yielding_action
@filters << "it didn't yield"
@filter_return_value
end
- def filter_three
- @filters << "filter_three"
+ def action_three
+ @filters << "action_three"
end
end
class ImplicitActionsController < ActionController::Base
- before_filter :find_only, :only => :edit
- before_filter :find_except, :except => :edit
+ before_action :find_only, :only => :edit
+ before_action :find_except, :except => :edit
private
@@ -528,7 +528,7 @@ class FilterTest < ActionController::TestCase
end
end
- def test_non_yielding_around_filters_not_returning_false_do_not_raise
+ def test_non_yielding_around_actions_not_returning_false_do_not_raise
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", true
assert_nothing_raised do
@@ -536,7 +536,7 @@ class FilterTest < ActionController::TestCase
end
end
- def test_non_yielding_around_filters_returning_false_do_not_raise
+ def test_non_yielding_around_actions_returning_false_do_not_raise
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", false
assert_nothing_raised do
@@ -544,64 +544,64 @@ class FilterTest < ActionController::TestCase
end
end
- def test_after_filters_are_not_run_if_around_filter_returns_false
+ def test_after_actions_are_not_run_if_around_action_returns_false
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", false
test_process(controller, "index")
assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
end
- def test_after_filters_are_not_run_if_around_filter_does_not_yield
+ def test_after_actions_are_not_run_if_around_action_does_not_yield
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", true
test_process(controller, "index")
assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
end
- def test_added_filter_to_inheritance_graph
- assert_equal [ :ensure_login ], TestController.before_filters
+ def test_added_action_to_inheritance_graph
+ assert_equal [ :ensure_login ], TestController.before_actions
end
def test_base_class_in_isolation
- assert_equal [ ], ActionController::Base.before_filters
+ assert_equal [ ], ActionController::Base.before_actions
end
- def test_prepending_filter
- assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters
+ def test_prepending_action
+ assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_actions
end
- def test_running_filters
+ def test_running_actions
test_process(PrependingController)
assert_equal %w( wonderful_life ensure_login ), assigns["ran_filter"]
end
- def test_running_filters_with_proc
+ def test_running_actions_with_proc
test_process(ProcController)
- assert assigns["ran_proc_filter"]
+ assert assigns["ran_proc_action"]
end
- def test_running_filters_with_implicit_proc
+ def test_running_actions_with_implicit_proc
test_process(ImplicitProcController)
- assert assigns["ran_proc_filter"]
+ assert assigns["ran_proc_action"]
end
- def test_running_filters_with_class
+ def test_running_actions_with_class
test_process(AuditController)
assert assigns["was_audited"]
end
- def test_running_anomolous_yet_valid_condition_filters
+ def test_running_anomolous_yet_valid_condition_actions
test_process(AnomolousYetValidConditionController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
- assert assigns["ran_class_filter"]
- assert assigns["ran_proc_filter1"]
- assert assigns["ran_proc_filter2"]
+ assert assigns["ran_class_action"]
+ assert assigns["ran_proc_action1"]
+ assert assigns["ran_proc_action2"]
- test_process(AnomolousYetValidConditionController, "show_without_filter")
+ test_process(AnomolousYetValidConditionController, "show_without_action")
assert_nil assigns["ran_filter"]
- assert !assigns["ran_class_filter"]
- assert !assigns["ran_proc_filter1"]
- assert !assigns["ran_proc_filter2"]
+ assert !assigns["ran_class_action"]
+ assert !assigns["ran_proc_action1"]
+ assert !assigns["ran_proc_action2"]
end
def test_running_conditional_options
@@ -614,59 +614,59 @@ class FilterTest < ActionController::TestCase
assert_equal %w( ensure_login ), assigns["ran_filter"]
end
- def test_skipping_class_filters
+ def test_skipping_class_actions
test_process(ClassController)
- assert_equal true, assigns["ran_class_filter"]
+ assert_equal true, assigns["ran_class_action"]
skipping_class_controller = Class.new(ClassController) do
- skip_before_filter ConditionalClassFilter
+ skip_before_action ConditionalClassFilter
end
test_process(skipping_class_controller)
- assert_nil assigns['ran_class_filter']
+ assert_nil assigns['ran_class_action']
end
- def test_running_collection_condition_filters
+ def test_running_collection_condition_actions
test_process(ConditionalCollectionFilterController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
- test_process(ConditionalCollectionFilterController, "show_without_filter")
+ test_process(ConditionalCollectionFilterController, "show_without_action")
assert_nil assigns["ran_filter"]
test_process(ConditionalCollectionFilterController, "another_action")
assert_nil assigns["ran_filter"]
end
- def test_running_only_condition_filters
+ def test_running_only_condition_actions
test_process(OnlyConditionSymController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
- test_process(OnlyConditionSymController, "show_without_filter")
+ test_process(OnlyConditionSymController, "show_without_action")
assert_nil assigns["ran_filter"]
test_process(OnlyConditionProcController)
- assert assigns["ran_proc_filter"]
- test_process(OnlyConditionProcController, "show_without_filter")
- assert !assigns["ran_proc_filter"]
+ assert assigns["ran_proc_action"]
+ test_process(OnlyConditionProcController, "show_without_action")
+ assert !assigns["ran_proc_action"]
test_process(OnlyConditionClassController)
- assert assigns["ran_class_filter"]
- test_process(OnlyConditionClassController, "show_without_filter")
- assert !assigns["ran_class_filter"]
+ assert assigns["ran_class_action"]
+ test_process(OnlyConditionClassController, "show_without_action")
+ assert !assigns["ran_class_action"]
end
- def test_running_except_condition_filters
+ def test_running_except_condition_actions
test_process(ExceptConditionSymController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
- test_process(ExceptConditionSymController, "show_without_filter")
+ test_process(ExceptConditionSymController, "show_without_action")
assert_nil assigns["ran_filter"]
test_process(ExceptConditionProcController)
- assert assigns["ran_proc_filter"]
- test_process(ExceptConditionProcController, "show_without_filter")
- assert !assigns["ran_proc_filter"]
+ assert assigns["ran_proc_action"]
+ test_process(ExceptConditionProcController, "show_without_action")
+ assert !assigns["ran_proc_action"]
test_process(ExceptConditionClassController)
- assert assigns["ran_class_filter"]
- test_process(ExceptConditionClassController, "show_without_filter")
- assert !assigns["ran_class_filter"]
+ assert assigns["ran_class_action"]
+ test_process(ExceptConditionClassController, "show_without_action")
+ assert !assigns["ran_class_action"]
end
def test_running_only_condition_and_conditional_options
@@ -674,70 +674,70 @@ class FilterTest < ActionController::TestCase
assert_not assigns["ran_conditional_index_proc"]
end
- def test_running_before_and_after_condition_filters
+ def test_running_before_and_after_condition_actions
test_process(BeforeAndAfterConditionController)
assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"]
- test_process(BeforeAndAfterConditionController, "show_without_filter")
+ test_process(BeforeAndAfterConditionController, "show_without_action")
assert_nil assigns["ran_filter"]
end
- def test_around_filter
+ def test_around_action
test_process(AroundFilterController)
assert assigns["before_ran"]
assert assigns["after_ran"]
end
- def test_before_after_class_filter
+ def test_before_after_class_action
test_process(BeforeAfterClassFilterController)
assert assigns["before_ran"]
assert assigns["after_ran"]
end
- def test_having_properties_in_around_filter
+ def test_having_properties_in_around_action
test_process(AroundFilterController)
assert_equal "before and after", assigns["execution_log"]
end
- def test_prepending_and_appending_around_filter
+ def test_prepending_and_appending_around_action
test_process(MixedFilterController)
assert_equal " before aroundfilter before procfilter before appended aroundfilter " +
" after appended aroundfilter after procfilter after aroundfilter ",
MixedFilterController.execution_log
end
- def test_rendering_breaks_filtering_chain
+ def test_rendering_breaks_actioning_chain
response = test_process(RenderingController)
assert_equal "something else", response.body
assert !assigns["ran_action"]
end
- def test_before_filter_rendering_breaks_filtering_chain_for_after_filter
+ def test_before_action_rendering_breaks_actioning_chain_for_after_action
test_process(RenderingController)
- assert_equal %w( before_filter_rendering ), assigns["ran_filter"]
+ assert_equal %w( before_action_rendering ), assigns["ran_filter"]
assert !assigns["ran_action"]
end
- def test_before_filter_redirects_breaks_filtering_chain_for_after_filter
- test_process(BeforeFilterRedirectionController)
+ def test_before_action_redirects_breaks_actioning_chain_for_after_action
+ test_process(BeforeActionRedirectionController)
assert_response :redirect
- assert_equal "http://test.host/filter_test/before_filter_redirection/target_of_redirection", redirect_to_url
- assert_equal %w( before_filter_redirects ), assigns["ran_filter"]
+ assert_equal "http://test.host/filter_test/before_action_redirection/target_of_redirection", redirect_to_url
+ assert_equal %w( before_action_redirects ), assigns["ran_filter"]
end
- def test_before_filter_rendering_breaks_filtering_chain_for_preprend_after_filter
- test_process(RenderingForPrependAfterFilterController)
- assert_equal %w( before_filter_rendering ), assigns["ran_filter"]
+ def test_before_action_rendering_breaks_actioning_chain_for_preprend_after_action
+ test_process(RenderingForPrependAfterActionController)
+ assert_equal %w( before_action_rendering ), assigns["ran_filter"]
assert !assigns["ran_action"]
end
- def test_before_filter_redirects_breaks_filtering_chain_for_preprend_after_filter
- test_process(BeforeFilterRedirectionForPrependAfterFilterController)
+ def test_before_action_redirects_breaks_actioning_chain_for_preprend_after_action
+ test_process(BeforeActionRedirectionForPrependAfterActionController)
assert_response :redirect
- assert_equal "http://test.host/filter_test/before_filter_redirection_for_prepend_after_filter/target_of_redirection", redirect_to_url
- assert_equal %w( before_filter_redirects ), assigns["ran_filter"]
+ assert_equal "http://test.host/filter_test/before_action_redirection_for_prepend_after_action/target_of_redirection", redirect_to_url
+ assert_equal %w( before_action_redirects ), assigns["ran_filter"]
end
- def test_filters_with_mixed_specialization_run_in_order
+ def test_actions_with_mixed_specialization_run_in_order
assert_nothing_raised do
response = test_process(MixedSpecializationController, 'bar')
assert_equal 'bar', response.body
@@ -758,7 +758,7 @@ class FilterTest < ActionController::TestCase
end
end
- def test_running_prepended_before_and_after_filter
+ def test_running_prepended_before_and_after_action
test_process(PrependingBeforeAndAfterController)
assert_equal %w( before_all between_before_all_and_after_all after_all ), assigns["ran_filter"]
end
@@ -775,26 +775,26 @@ class FilterTest < ActionController::TestCase
assert_equal %w( find_record ensure_login ), assigns["ran_filter"]
end
- def test_conditional_skipping_of_filters
+ def test_conditional_skipping_of_actions
test_process(ConditionalSkippingController, "login")
assert_nil assigns["ran_filter"]
test_process(ConditionalSkippingController, "change_password")
assert_equal %w( ensure_login find_user ), assigns["ran_filter"]
test_process(ConditionalSkippingController, "login")
- assert !@controller.instance_variable_defined?("@ran_after_filter")
+ assert !@controller.instance_variable_defined?("@ran_after_action")
test_process(ConditionalSkippingController, "change_password")
- assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_filter")
+ assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_action")
end
- def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
+ def test_conditional_skipping_of_actions_when_parent_action_is_also_conditional
test_process(ChildOfConditionalParentController)
assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
test_process(ChildOfConditionalParentController, 'another_action')
assert_nil assigns['ran_filter']
end
- def test_condition_skipping_of_filters_when_siblings_also_have_conditions
+ def test_condition_skipping_of_actions_when_siblings_also_have_conditions
test_process(ChildOfConditionalParentController)
assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
test_process(AnotherChildOfConditionalParentController)
@@ -808,7 +808,7 @@ class FilterTest < ActionController::TestCase
assert_nil assigns['ran_filter']
end
- def test_a_rescuing_around_filter
+ def test_a_rescuing_around_action
response = nil
assert_nothing_raised do
response = test_process(RescuedController)
@@ -818,7 +818,7 @@ class FilterTest < ActionController::TestCase
assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body)
end
- def test_filters_obey_only_and_except_for_implicit_actions
+ def test_actions_obey_only_and_except_for_implicit_actions
test_process(ImplicitActionsController, 'show')
assert_equal 'Except', assigns(:except)
assert_nil assigns(:only)
@@ -852,7 +852,7 @@ class PostsController < ActionController::Base
include AroundExceptions
end
- module_eval %w(raises_before raises_after raises_both no_raise no_filter).map { |action| "def #{action}; default_action end" }.join("\n")
+ module_eval %w(raises_before raises_after raises_both no_raise no_action).map { |action| "def #{action}; default_action end" }.join("\n")
private
def default_action
@@ -861,9 +861,9 @@ class PostsController < ActionController::Base
end
class ControllerWithSymbolAsFilter < PostsController
- around_filter :raise_before, :only => :raises_before
- around_filter :raise_after, :only => :raises_after
- around_filter :without_exception, :only => :no_raise
+ around_action :raise_before, :only => :raises_before
+ around_action :raise_after, :only => :raises_after
+ around_action :without_exception, :only => :no_raise
private
def raise_before
@@ -895,7 +895,7 @@ class ControllerWithFilterClass < PostsController
end
end
- around_filter YieldingFilter, :only => :raises_after
+ around_action YieldingFilter, :only => :raises_after
end
class ControllerWithFilterInstance < PostsController
@@ -906,11 +906,11 @@ class ControllerWithFilterInstance < PostsController
end
end
- around_filter YieldingFilter.new, :only => :raises_after
+ around_action YieldingFilter.new, :only => :raises_after
end
class ControllerWithProcFilter < PostsController
- around_filter(:only => :no_raise) do |c,b|
+ around_action(:only => :no_raise) do |c,b|
c.instance_variable_set(:"@before", true)
b.call
c.instance_variable_set(:"@after", true)
@@ -918,14 +918,14 @@ class ControllerWithProcFilter < PostsController
end
class ControllerWithNestedFilters < ControllerWithSymbolAsFilter
- around_filter :raise_before, :raise_after, :without_exception, :only => :raises_both
+ around_action :raise_before, :raise_after, :without_exception, :only => :raises_both
end
class ControllerWithAllTypesOfFilters < PostsController
- before_filter :before
- around_filter :around
- after_filter :after
- around_filter :around_again
+ before_action :before
+ around_action :around
+ after_action :after
+ around_action :around_again
private
def before
@@ -951,8 +951,8 @@ class ControllerWithAllTypesOfFilters < PostsController
end
class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters
- skip_filter :around_again
- skip_filter :after
+ skip_action_callback :around_again
+ skip_action_callback :after
end
class YieldingAroundFiltersTest < ActionController::TestCase
@@ -963,7 +963,7 @@ class YieldingAroundFiltersTest < ActionController::TestCase
assert_nothing_raised { test_process(controller,'no_raise') }
assert_nothing_raised { test_process(controller,'raises_before') }
assert_nothing_raised { test_process(controller,'raises_after') }
- assert_nothing_raised { test_process(controller,'no_filter') }
+ assert_nothing_raised { test_process(controller,'no_action') }
end
def test_with_symbol
@@ -992,7 +992,7 @@ class YieldingAroundFiltersTest < ActionController::TestCase
assert assigns['after']
end
- def test_nested_filters
+ def test_nested_actions
controller = ControllerWithNestedFilters
assert_nothing_raised do
begin
@@ -1008,31 +1008,31 @@ class YieldingAroundFiltersTest < ActionController::TestCase
end
end
- def test_filter_order_with_all_filter_types
+ def test_action_order_with_all_action_types
test_process(ControllerWithAllTypesOfFilters,'no_raise')
assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)', assigns['ran_filter'].join(' ')
end
- def test_filter_order_with_skip_filter_method
+ def test_action_order_with_skip_action_method
test_process(ControllerWithTwoLessFilters,'no_raise')
assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ')
end
- def test_first_filter_in_multiple_before_filter_chain_halts
+ def test_first_action_in_multiple_before_action_chain_halts
controller = ::FilterTest::TestMultipleFiltersController.new
response = test_process(controller, 'fail_1')
assert_equal ' ', response.body
assert_equal 1, controller.instance_variable_get(:@try)
end
- def test_second_filter_in_multiple_before_filter_chain_halts
+ def test_second_action_in_multiple_before_action_chain_halts
controller = ::FilterTest::TestMultipleFiltersController.new
response = test_process(controller, 'fail_2')
assert_equal ' ', response.body
assert_equal 2, controller.instance_variable_get(:@try)
end
- def test_last_filter_in_multiple_before_filter_chain_halts
+ def test_last_action_in_multiple_before_action_chain_halts
controller = ::FilterTest::TestMultipleFiltersController.new
response = test_process(controller, 'fail_3')
assert_equal ' ', response.body
diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb
index 90548d4294..9052fc6962 100644
--- a/actionpack/test/controller/http_basic_authentication_test.rb
+++ b/actionpack/test/controller/http_basic_authentication_test.rb
@@ -129,6 +129,13 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
assert_response :unauthorized
end
+ test "authentication request with wrong scheme" do
+ header = 'Bearer ' + encode_credentials('David', 'Goliath').split(' ', 2)[1]
+ @request.env['HTTP_AUTHORIZATION'] = header
+ get :search
+ assert_response :unauthorized
+ end
+
private
def encode_credentials(username, password)
diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb
index 86b94652ce..8c6c8a0aa7 100644
--- a/actionpack/test/controller/http_token_authentication_test.rb
+++ b/actionpack/test/controller/http_token_authentication_test.rb
@@ -132,13 +132,50 @@ class HttpTokenAuthenticationTest < ActionController::TestCase
assert_equal(expected, actual)
end
- private
+ test "token_and_options returns empty string with empty token" do
+ token = ''
+ actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token)).first
+ expected = token
+ assert_equal(expected, actual)
+ end
- def sample_request(token)
- @sample_request ||= OpenStruct.new authorization: %{Token token="#{token}"}
+ test "token_and_options returns correct token with nounce option" do
+ token = "rcHu+HzSFw89Ypyhn/896A="
+ nonce_hash = {nonce: "123abc"}
+ actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token, nonce_hash))
+ expected_token = token
+ expected_nonce = {"nonce" => nonce_hash[:nonce]}
+ assert_equal(expected_token, actual.first)
+ assert_equal(expected_nonce, actual.last)
end
- def encode_credentials(token, options = {})
- ActionController::HttpAuthentication::Token.encode_credentials(token, options)
+ test "token_and_options returns nil with no value after the equal sign" do
+ actual = ActionController::HttpAuthentication::Token.token_and_options(malformed_request).first
+ expected = nil
+ assert_equal(expected, actual)
+ end
+
+ test "raw_params returns a tuple of two key value pair strings" do
+ auth = sample_request("rcHu+HzSFw89Ypyhn/896A=").authorization.to_s
+ actual = ActionController::HttpAuthentication::Token.raw_params(auth)
+ expected = ["token=\"rcHu+HzSFw89Ypyhn/896A=\"", "nonce=\"def\""]
+ assert_equal(expected, actual)
end
+
+ private
+
+ def sample_request(token, options = {nonce: "def"})
+ authorization = options.inject([%{Token token="#{token}"}]) do |arr, (k, v)|
+ arr << "#{k}=\"#{v}\""
+ end.join(", ")
+ @sample_request ||= OpenStruct.new authorization: authorization
+ end
+
+ def malformed_request
+ @malformed_request ||= OpenStruct.new authorization: %{Token token=}
+ end
+
+ def encode_credentials(token, options = {})
+ ActionController::HttpAuthentication::Token.encode_credentials(token, options)
+ end
end
diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb
index 1dca36374a..0500b7c789 100644
--- a/actionpack/test/controller/live_stream_test.rb
+++ b/actionpack/test/controller/live_stream_test.rb
@@ -202,6 +202,39 @@ module ActionController
response.stream.write ''
response.stream.write params[:widget][:didnt_check_for_nil]
end
+
+ def overfill_buffer_and_die
+ # Write until the buffer is full. It doesn't expose that
+ # information directly, so we must hard-code its size:
+ 10.times do
+ response.stream.write '.'
+ end
+ # .. plus one more, because the #each frees up a slot:
+ response.stream.write '.'
+
+ latch.release
+
+ # This write will block, and eventually raise
+ response.stream.write 'x'
+
+ 20.times do
+ response.stream.write '.'
+ end
+ end
+
+ def ignore_client_disconnect
+ response.stream.ignore_disconnect = true
+
+ response.stream.write '' # commit
+
+ # These writes will be ignored
+ 15.times do
+ response.stream.write 'x'
+ end
+
+ logger.info 'Work complete'
+ latch.release
+ end
end
tests TestController
@@ -264,6 +297,62 @@ module ActionController
assert t.join(3), 'timeout expired before the thread terminated'
end
+ def test_abort_with_full_buffer
+ @controller.latch = ActiveSupport::Concurrency::Latch.new
+
+ @request.parameters[:format] = 'plain'
+ @controller.request = @request
+ @controller.response = @response
+
+ got_error = ActiveSupport::Concurrency::Latch.new
+ @response.stream.on_error do
+ ActionController::Base.logger.warn 'Error while streaming'
+ got_error.release
+ end
+
+ t = Thread.new(@response) { |resp|
+ resp.await_commit
+ _, _, body = resp.to_a
+ body.each do |part|
+ @controller.latch.await
+ body.close
+ break
+ end
+ }
+
+ capture_log_output do |output|
+ @controller.process :overfill_buffer_and_die
+ t.join
+ got_error.await
+ assert_match 'Error while streaming', output.rewind && output.read
+ end
+ end
+
+ def test_ignore_client_disconnect
+ @controller.latch = ActiveSupport::Concurrency::Latch.new
+
+ @controller.request = @request
+ @controller.response = @response
+
+ t = Thread.new(@response) { |resp|
+ resp.await_commit
+ _, _, body = resp.to_a
+ body.each do |part|
+ body.close
+ break
+ end
+ }
+
+ capture_log_output do |output|
+ @controller.process :ignore_client_disconnect
+ t.join
+ Timeout.timeout(3) do
+ @controller.latch.await
+ end
+ assert_match 'Work complete', output.rewind && output.read
+ end
+ end
+
def test_thread_locals_get_copied
@controller.tc = self
Thread.current[:originating_thread] = Thread.current.object_id
diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb
index c95ef8a0c7..27871ef351 100644
--- a/actionpack/test/controller/localized_templates_test.rb
+++ b/actionpack/test/controller/localized_templates_test.rb
@@ -8,22 +8,24 @@ end
class LocalizedTemplatesTest < ActionController::TestCase
tests LocalizedController
+ setup do
+ @old_locale = I18n.locale
+ end
+
+ teardown do
+ I18n.locale = @old_locale
+ end
+
def test_localized_template_is_used
- old_locale = I18n.locale
I18n.locale = :de
get :hello_world
assert_equal "Gutten Tag", @response.body
- ensure
- I18n.locale = old_locale
end
def test_default_locale_template_is_used_when_locale_is_missing
- old_locale = I18n.locale
I18n.locale = :dk
get :hello_world
assert_equal "Hello World", @response.body
- ensure
- I18n.locale = old_locale
end
def test_use_fallback_locales
@@ -36,13 +38,9 @@ class LocalizedTemplatesTest < ActionController::TestCase
end
def test_localized_template_has_correct_header_with_no_format_in_template_name
- old_locale = I18n.locale
I18n.locale = :it
-
get :hello_world
assert_equal "Ciao Mondo", @response.body
assert_equal "text/html", @response.content_type
- ensure
- I18n.locale = old_locale
end
end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 41503e11a8..c89b95de3b 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -128,6 +128,12 @@ class RespondToController < ActionController::Base
end
end
+ def json_with_callback
+ respond_to do |type|
+ type.json { render :json => 'JS', :callback => 'alert' }
+ end
+ end
+
def iphone_with_html_response_type
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
@@ -511,6 +517,13 @@ class RespondToControllerTest < ActionController::TestCase
assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body
end
+ def test_json_with_callback_sets_javascript_content_type
+ @request.accept = 'application/json'
+ get :json_with_callback
+ assert_equal 'alert(JS)', @response.body
+ assert_equal 'text/javascript', @response.content_type
+ end
+
def test_xhr
xhr :get, :js_or_html
assert_equal 'JS', @response.body
diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb
index 416b3b81a5..115f3b2f41 100644
--- a/actionpack/test/controller/mime/respond_with_test.rb
+++ b/actionpack/test/controller/mime/respond_with_test.rb
@@ -2,6 +2,10 @@ require 'abstract_unit'
require 'controller/fake_models'
class RespondWithController < ActionController::Base
+ class CustomerWithJson < Customer
+ def to_json; super; end
+ end
+
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' ]
@@ -38,6 +42,10 @@ class RespondWithController < ActionController::Base
respond_with(resource, :location => "http://test.host/", :status => :created)
end
+ def using_resource_with_json
+ respond_with(CustomerWithJson.new("david", request.delete? ? nil : 13))
+ end
+
def using_invalid_resource_with_template
respond_with(resource)
end
@@ -380,9 +388,8 @@ class RespondWithControllerTest < ActionController::TestCase
end
def test_using_resource_for_put_with_json_yields_no_content_on_success
- Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
@request.accept = "application/json"
- put :using_resource
+ put :using_resource_with_json
assert_equal "application/json", @response.content_type
assert_equal 204, @response.status
assert_equal "", @response.body
@@ -431,10 +438,9 @@ class RespondWithControllerTest < ActionController::TestCase
end
def test_using_resource_for_delete_with_json_yields_no_content_on_success
- Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
Customer.any_instance.stubs(:destroyed?).returns(true)
@request.accept = "application/json"
- delete :using_resource
+ delete :using_resource_with_json
assert_equal "application/json", @response.content_type
assert_equal 204, @response.status
assert_equal "", @response.body
@@ -643,6 +649,8 @@ class RespondWithControllerTest < ActionController::TestCase
get :index, format: 'csv'
assert_equal Mime::CSV, @response.content_type
assert_equal "c,s,v", @response.body
+ ensure
+ ActionController::Renderers.remove :csv
end
def test_raises_missing_renderer_if_an_api_behavior_with_no_renderer
@@ -652,6 +660,23 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
+ def test_removing_renderers
+ ActionController::Renderers.add :csv do |obj, options|
+ send_data obj.to_csv, type: Mime::CSV
+ end
+ @controller = CsvRespondWithController.new
+ @request.accept = "text/csv"
+ get :index, format: 'csv'
+ assert_equal Mime::CSV, @response.content_type
+
+ ActionController::Renderers.remove :csv
+ assert_raise ActionController::MissingRenderer do
+ get :index, format: 'csv'
+ end
+ ensure
+ ActionController::Renderers.remove :csv
+ end
+
def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called
@controller = EmptyRespondWithController.new
@request.accept = "*/*"
diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb
index 7396c850ad..246ba099af 100644
--- a/actionpack/test/controller/new_base/bare_metal_test.rb
+++ b/actionpack/test/controller/new_base/bare_metal_test.rb
@@ -2,6 +2,8 @@ require "abstract_unit"
module BareMetalTest
class BareController < ActionController::Metal
+ include ActionController::RackDelegation
+
def index
self.response_body = "Hello world"
end
@@ -81,8 +83,8 @@ module BareMetalTest
assert_nil headers['Content-Length']
end
- test "head :continue (101) does not return a content-type header" do
- headers = HeadController.action(:continue).call(Rack::MockRequest.env_for("/")).second
+ test "head :switching_protocols (101) does not return a content-type header" do
+ headers = HeadController.action(:switching_protocols).call(Rack::MockRequest.env_for("/")).second
assert_nil headers['Content-Type']
assert_nil headers['Content-Length']
end
diff --git a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb
new file mode 100644
index 0000000000..059f310d49
--- /dev/null
+++ b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb
@@ -0,0 +1,29 @@
+require 'abstract_unit'
+require 'action_controller/metal/strong_parameters'
+
+class AlwaysPermittedParametersTest < ActiveSupport::TestCase
+ def setup
+ ActionController::Parameters.action_on_unpermitted_parameters = :raise
+ ActionController::Parameters.always_permitted_parameters = %w( controller action format )
+ end
+
+ def teardown
+ ActionController::Parameters.action_on_unpermitted_parameters = false
+ ActionController::Parameters.always_permitted_parameters = %w( controller action )
+ end
+
+ test "shows deprecations warning on NEVER_UNPERMITTED_PARAMS" do
+ assert_deprecated do
+ ActionController::Parameters::NEVER_UNPERMITTED_PARAMS
+ end
+ end
+
+ test "permits parameters that are whitelisted" do
+ params = ActionController::Parameters.new({
+ book: { pages: 65 },
+ format: "json"
+ })
+ permitted = params.permit book: [:pages]
+ assert permitted.permitted?
+ end
+end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 33a91d72d9..aa894ffa17 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -167,9 +167,26 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
end
+ # Strong params has an optimization to avoid looping every time you read
+ # a key whose value is an array and building a new object. We check that
+ # optimization here.
test 'arrays are converted at most once' do
params = ActionController::Parameters.new(foo: [{}])
- assert params[:foo].equal?(params[:foo])
+ assert_same params[:foo], params[:foo]
+ end
+
+ # Strong params has an internal cache to avoid duplicated loops in the most
+ # common usage pattern. See the docs of the method `converted_arrays`.
+ #
+ # This test checks that if we push a hash to an array (in-place modification)
+ # the cache does not get fooled, the hash is still wrapped as strong params,
+ # and not permitted.
+ test 'mutated arrays are detected' do
+ params = ActionController::Parameters.new(users: [{id: 1}])
+
+ permitted = params.permit(users: [:id])
+ permitted[:users] << {injected: 1}
+ assert_not permitted[:users].last.permitted?
end
test "fetch doesnt raise ParameterMissing exception if there is a default" do
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index 11ccb6cf3b..645ecae220 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -337,14 +337,26 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase
tests ParamswrappernewsController
def test_uses_model_attribute_names_with_irregular_inflection
- ActiveSupport::Inflector.inflections do |inflect|
- inflect.irregular 'paramswrappernews_item', 'paramswrappernews'
- end
+ with_dup do
+ ActiveSupport::Inflector.inflections do |inflect|
+ inflect.irregular 'paramswrappernews_item', 'paramswrappernews'
+ end
- with_default_wrapper_options do
- @request.env['CONTENT_TYPE'] = 'application/json'
- post :parse, { 'username' => 'sikachu', 'test_attr' => 'test_value' }
- assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }})
+ with_default_wrapper_options do
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, { 'username' => 'sikachu', 'test_attr' => 'test_value' }
+ assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }})
+ end
end
end
+
+ private
+
+ def with_dup
+ original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en]
+ ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup)
+ yield
+ ensure
+ ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original)
+ end
end
diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb
index b5e74e373d..af50e11261 100644
--- a/actionpack/test/controller/render_other_test.rb
+++ b/actionpack/test/controller/render_other_test.rb
@@ -1,9 +1,5 @@
require 'abstract_unit'
-ActionController.add_renderer :simon do |says, options|
- self.content_type = Mime::TEXT
- self.response_body = "Simon says: #{says}"
-end
class RenderOtherTest < ActionController::TestCase
class TestController < ActionController::Base
@@ -15,7 +11,14 @@ class RenderOtherTest < ActionController::TestCase
tests TestController
def test_using_custom_render_option
+ ActionController.add_renderer :simon do |says, options|
+ self.content_type = Mime::TEXT
+ self.response_body = "Simon says: #{says}"
+ end
+
get :render_simon_says
assert_equal "Simon says: foo", @response.body
+ ensure
+ ActionController.remove_renderer :simon
end
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 26806fb03f..9926130c02 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -242,6 +242,8 @@ class MetalTestController < ActionController::Metal
include AbstractController::Rendering
include ActionView::Rendering
include ActionController::Rendering
+ include ActionController::RackDelegation
+
def accessing_logger_in_template
render :inline => "<%= logger.class %>"
@@ -387,10 +389,6 @@ end
class EtagRenderTest < ActionController::TestCase
tests TestControllerWithExtraEtags
- def setup
- super
- end
-
def test_multiple_etags
@request.if_none_match = etag(["123", 'ab', :cde, [:f]])
get :fresh
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 07c2115832..2a5aad9c0e 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -127,11 +127,12 @@ module RequestForgeryProtectionTests
@token = "cf50faa3fe97702ca1ae"
SecureRandom.stubs(:base64).returns(@token)
+ @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token
ActionController::Base.request_forgery_protection_token = :custom_authenticity_token
end
def teardown
- ActionController::Base.request_forgery_protection_token = nil
+ ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token
end
def test_should_render_form_with_token_tag
@@ -376,11 +377,12 @@ class RequestForgeryProtectionControllerUsingResetSessionTest < ActionController
include RequestForgeryProtectionTests
setup do
+ @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token
ActionController::Base.request_forgery_protection_token = :custom_authenticity_token
end
teardown do
- ActionController::Base.request_forgery_protection_token = nil
+ ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token
end
test 'should emit a csrf-param meta tag and a csrf-token meta tag' do
@@ -465,11 +467,12 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase
@old_logger = ActionController::Base.logger
@logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
@token = "foobar"
+ @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token
ActionController::Base.request_forgery_protection_token = @token
end
def teardown
- ActionController::Base.request_forgery_protection_token = nil
+ ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token
super
end
diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb
index 25d0337212..6803dbbb62 100644
--- a/actionpack/test/controller/required_params_test.rb
+++ b/actionpack/test/controller/required_params_test.rb
@@ -24,10 +24,26 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase
post :create, { book: { name: "Mjallo!" } }
assert_response :ok
end
+
+ test "required parameters with false value will not raise" do
+ post :create, { book: { name: false } }
+ assert_response :ok
+ end
end
class ParametersRequireTest < ActiveSupport::TestCase
- test "required parameters must be present not merely not nil" do
+
+ test "required parameters should accept and return false value" do
+ assert_equal(false, ActionController::Parameters.new(person: false).require(:person))
+ end
+
+ test "required parameters must not be nil" do
+ assert_raises(ActionController::ParameterMissing) do
+ ActionController::Parameters.new(person: nil).require(:person)
+ end
+ end
+
+ test "required parameters must not be empty" do
assert_raises(ActionController::ParameterMissing) do
ActionController::Parameters.new(person: {}).require(:person)
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index b22bc2dc25..721dad4dd9 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -87,7 +87,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_symbols_with_dashes
rs.draw do
get '/:artist/:song-omg', :to => lambda { |env|
- resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters
[200, {}, [resp]]
}
end
@@ -99,7 +99,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_id_with_dash
rs.draw do
get '/journey/:id', :to => lambda { |env|
- resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters
[200, {}, [resp]]
}
end
@@ -111,7 +111,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_dash_with_custom_regexp
rs.draw do
get '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env|
- resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters
[200, {}, [resp]]
}
end
@@ -124,7 +124,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_pre_dash
rs.draw do
get '/:artist/omg-:song', :to => lambda { |env|
- resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters
[200, {}, [resp]]
}
end
@@ -136,7 +136,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_pre_dash_with_custom_regexp
rs.draw do
get '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env|
- resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters
[200, {}, [resp]]
}
end
@@ -243,6 +243,32 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
assert_equal 'clients', get(URI('http://clients.example.org/'))
end
+ def test_scoped_lambda
+ scope_called = false
+ rs.draw do
+ scope '/foo', :constraints => lambda { |req| scope_called = true } do
+ get '/', :to => lambda { |env| [200, {}, %w{default}] }
+ end
+ end
+
+ assert_equal 'default', get(URI('http://www.example.org/foo/'))
+ assert scope_called, "scope constraint should be called"
+ end
+
+ def test_scoped_lambda_with_get_lambda
+ inner_called = false
+
+ rs.draw do
+ scope '/foo', :constraints => lambda { |req| flunk "should not be called" } do
+ get '/', :constraints => lambda { |req| inner_called = true },
+ :to => lambda { |env| [200, {}, %w{default}] }
+ end
+ end
+
+ assert_equal 'default', get(URI('http://www.example.org/foo/'))
+ assert inner_called, "inner constraint should be called"
+ end
+
def test_empty_string_match
rs.draw do
get '/:username', :constraints => { :username => /[^\/]+/ },
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index aee139b95e..c002cf4d8f 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -9,6 +9,7 @@ end
class SendFileController < ActionController::Base
include TestFileUtils
+ include ActionController::Testing
layout "layouts/standard" # to make sure layouts don't interfere
attr_writer :options
@@ -32,8 +33,6 @@ end
class SendFileTest < ActionController::TestCase
include TestFileUtils
- Mime::Type.register "image/png", :png unless defined? Mime::PNG
-
def setup
@controller = SendFileController.new
@request = ActionController::TestRequest.new
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index fbc10baf21..3b3b15c061 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -164,7 +164,7 @@ XML
end
class DefaultUrlOptionsCachingController < ActionController::Base
- before_filter { @dynamic_opt = 'opt' }
+ before_action { @dynamic_opt = 'opt' }
def test_url_options_reset
render text: url_for(params)
@@ -662,7 +662,7 @@ XML
def test_id_converted_to_string
get :test_params, :id => 20, :foo => Object.new
- assert_kind_of String, @request.path_parameters['id']
+ assert_kind_of String, @request.path_parameters[:id]
end
def test_array_path_parameter_handled_properly
@@ -673,17 +673,17 @@ XML
end
get :test_params, :path => ['hello', 'world']
- assert_equal ['hello', 'world'], @request.path_parameters['path']
- assert_equal 'hello/world', @request.path_parameters['path'].to_param
+ assert_equal ['hello', 'world'], @request.path_parameters[:path]
+ assert_equal 'hello/world', @request.path_parameters[:path].to_param
end
end
def test_assert_realistic_path_parameters
get :test_params, :id => 20, :foo => Object.new
- # All elements of path_parameters should use string keys
+ # All elements of path_parameters should use Symbol keys
@request.path_parameters.keys.each do |key|
- assert_kind_of String, key
+ assert_kind_of Symbol, key
end
end
@@ -737,12 +737,12 @@ XML
assert_equal "baz", @request.filtered_parameters[:foo]
end
- def test_symbolized_path_params_reset_after_request
+ def test_path_params_reset_after_request
get :test_params, :id => "foo"
- assert_equal "foo", @request.symbolized_path_parameters[:id]
+ assert_equal "foo", @request.path_parameters[:id]
@request.recycle!
get :test_params
- assert_nil @request.symbolized_path_parameters[:id]
+ assert_nil @request.path_parameters[:id]
end
def test_request_protocol_is_reset_after_request
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 0c6df16325..7210c68e73 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -11,6 +11,26 @@ module AbstractController
W.default_url_options.clear
end
+ def test_nested_optional
+ klass = Class.new {
+ include ActionDispatch::Routing::RouteSet.new.tap { |r|
+ r.draw {
+ get "/foo/(:bar/(:baz))/:zot", :as => 'fun',
+ :controller => :articles,
+ :action => :index
+ }
+ }.url_helpers
+ self.default_url_options[:host] = 'example.com'
+ }
+
+ path = klass.new.fun_path({:controller => :articles,
+ :baz => "baz",
+ :zot => "zot",
+ :only_path => true })
+ # :bar key isn't provided
+ assert_equal '/foo/zot', path
+ end
+
def add_host!
W.default_url_options[:host] = 'www.basecamphq.com'
end
@@ -75,7 +95,7 @@ module AbstractController
end
def test_subdomain_may_be_object
- model = mock(:to_param => 'api')
+ model = Class.new { def self.to_param; 'api'; end }
add_host!
assert_equal('http://api.basecamphq.com/c/a/i',
W.new.url_for(:subdomain => model, :controller => 'c', :action => 'a', :id => 'i')
diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb
index 58457b0c28..d8d3209dac 100644
--- a/actionpack/test/dispatch/mapper_test.rb
+++ b/actionpack/test/dispatch/mapper_test.rb
@@ -38,7 +38,7 @@ module ActionDispatch
def test_mapping_requirements
options = { :controller => 'foo', :action => 'bar', :via => :get }
- m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options
+ m = Mapper::Mapping.build({}, '/store/:name(*rest)', options)
_, _, requirements, _ = m.to_route
assert_equal(/.+?/, requirements[:rest])
end
@@ -72,7 +72,7 @@ module ActionDispatch
mapper = Mapper.new fakeset
mapper.get '/*path/foo/:bar', :to => 'pages#show'
assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info]
- assert_nil fakeset.requirements.first[:path]
+ assert_equal(/.+?/, fakeset.requirements.first[:path])
end
def test_map_wildcard_with_multiple_wildcard
@@ -80,7 +80,7 @@ module ActionDispatch
mapper = Mapper.new fakeset
mapper.get '/*foo/*bar', :to => 'pages#show'
assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info]
- assert_nil fakeset.requirements.first[:foo]
+ assert_equal(/.+?/, fakeset.requirements.first[:foo])
assert_equal(/.+?/, fakeset.requirements.first[:bar])
end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 981cf2426e..d29cc8473e 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -1,8 +1,6 @@
require 'abstract_unit'
class MimeTypeTest < ActiveSupport::TestCase
- Mime::Type.register "image/png", :png unless defined? Mime::PNG
- Mime::Type.register "application/pdf", :pdf unless defined? Mime::PDF
test "parse single" do
Mime::LOOKUP.keys.each do |mime_type|
diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb
index cdf00d84fb..ff4b644c16 100644
--- a/actionpack/test/dispatch/mount_test.rb
+++ b/actionpack/test/dispatch/mount_test.rb
@@ -31,10 +31,13 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
resources :users do
mount FakeEngine, :at => "/fakeengine", :as => :fake_mounted_at_resource
end
+
+ mount SprocketsApp, :at => "/", :via => :get
end
+ APP = RoutedRackApp.new Router
def app
- Router
+ APP
end
def test_app_name_is_properly_generated_when_engine_is_mounted_in_resources
@@ -44,6 +47,11 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
"A named route should be defined with a parent's prefix"
end
+ def test_mounting_at_root_path
+ get "/omg"
+ assert_equal " -- /omg", response.body
+ end
+
def test_mounting_sets_script_name
get "/sprockets/omg"
assert_equal "/sprockets -- /omg", response.body
diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb
index ce9ccfcee8..62e8197e20 100644
--- a/actionpack/test/dispatch/reloader_test.rb
+++ b/actionpack/test/dispatch/reloader_test.rb
@@ -3,6 +3,11 @@ require 'abstract_unit'
class ReloaderTest < ActiveSupport::TestCase
Reloader = ActionDispatch::Reloader
+ teardown do
+ Reloader.reset_callbacks :prepare
+ Reloader.reset_callbacks :cleanup
+ end
+
def test_prepare_callbacks
a = b = c = nil
Reloader.to_prepare { |*args| a = b = c = 1 }
diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index 46c3e3d19d..926472163e 100644
--- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -149,7 +149,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
test "does not raise EOFError on GET request with multipart content-type" do
with_routing do |set|
set.draw do
- get ':action', to: 'multipart_params_parsing_test/test'
+ get ':action', controller: 'multipart_params_parsing_test/test'
end
headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" }
get "/parse", {}, headers
@@ -178,7 +178,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- post ':action', :to => 'multipart_params_parsing_test/test'
+ post ':action', :controller => 'multipart_params_parsing_test/test'
end
yield
end
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index d82493140f..4e99c26e03 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -105,6 +105,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
end
test "perform_deep_munge" do
+ old_perform_deep_munge = ActionDispatch::Request::Utils.perform_deep_munge
ActionDispatch::Request::Utils.perform_deep_munge = false
begin
assert_parses({"action" => nil}, "action")
@@ -115,7 +116,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
assert_parses({"action" => {"foo" => [{"bar" => nil}]}}, "action[foo][][bar]")
assert_parses({"action" => ['1',nil]}, "action[]=1&action[]")
ensure
- ActionDispatch::Request::Utils.perform_deep_munge = true
+ ActionDispatch::Request::Utils.perform_deep_munge = old_perform_deep_munge
end
end
diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
index 9a77454f30..1de05cbf09 100644
--- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
@@ -130,10 +130,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
end
test "ambiguous params returns a bad request" do
- with_routing do |set|
- set.draw do
- post ':action', to: ::UrlEncodedParamsParsingTest::TestController
- end
+ with_test_routing do
post "/parse", "foo[]=bar&foo[4]=bar"
assert_response :bad_request
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 0e7e34fa8b..1ef2b062dd 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -811,6 +811,7 @@ class RequestFormat < BaseRequestTest
end
test "ignore_accept_header" do
+ old_ignore_accept_header = ActionDispatch::Request.ignore_accept_header
ActionDispatch::Request.ignore_accept_header = true
begin
@@ -840,7 +841,7 @@ class RequestFormat < BaseRequestTest
request.expects(:parameters).at_least_once.returns({:format => :json})
assert_equal [ Mime::JSON ], request.formats
ensure
- ActionDispatch::Request.ignore_accept_header = false
+ ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header
end
end
end
@@ -1071,7 +1072,7 @@ class RequestEtag < BaseRequestTest
end
end
-class RequestVarient < BaseRequestTest
+class RequestVariant < BaseRequestTest
test "setting variant" do
request = stub_request
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 959a3bc5cd..187b9a2420 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -178,6 +178,7 @@ class ResponseTest < ActiveSupport::TestCase
end
test "read x_frame_options, x_content_type_options and x_xss_protection" do
+ original_default_headers = ActionDispatch::Response.default_headers
begin
ActionDispatch::Response.default_headers = {
'X-Frame-Options' => 'DENY',
@@ -193,11 +194,12 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal('nosniff', resp.headers['X-Content-Type-Options'])
assert_equal('1;', resp.headers['X-XSS-Protection'])
ensure
- ActionDispatch::Response.default_headers = nil
+ ActionDispatch::Response.default_headers = original_default_headers
end
end
test "read custom default_header" do
+ original_default_headers = ActionDispatch::Response.default_headers
begin
ActionDispatch::Response.default_headers = {
'X-XX-XXXX' => 'Here is my phone number'
@@ -209,7 +211,7 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal('Here is my phone number', resp.headers['X-XX-XXXX'])
ensure
- ActionDispatch::Response.default_headers = nil
+ ActionDispatch::Response.default_headers = original_default_headers
end
end
diff --git a/actionpack/test/dispatch/routing/concerns_test.rb b/actionpack/test/dispatch/routing/concerns_test.rb
index 9f37701656..7ef513b0c8 100644
--- a/actionpack/test/dispatch/routing/concerns_test.rb
+++ b/actionpack/test/dispatch/routing/concerns_test.rb
@@ -36,7 +36,8 @@ class RoutingConcernsTest < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = RoutedRackApp.new Routes
+ def app; APP end
def test_accessing_concern_from_resources
get "/posts/1/comments"
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index cae6b312b6..269c7b4159 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -99,6 +99,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_namespace_without_controller_segment
+ draw do
+ namespace :admin do
+ get 'hello/:controllers/:action'
+ end
+ end
+ get '/admin/hello/foo/new'
+ assert_equal 'foo', @request.params["controllers"]
+ end
+
def test_session_singleton_resource
draw do
resource :session do
@@ -351,8 +361,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
draw do
controller(:global) do
get 'global/hide_notice'
- get 'global/export', :to => :export, :as => :export_request
- get '/export/:id/:file', :to => :export, :as => :export_download, :constraints => { :file => /.*/ }
+ get 'global/export', :action => :export, :as => :export_request
+ get '/export/:id/:file', :action => :export, :as => :export_download, :constraints => { :file => /.*/ }
get 'global/:action'
end
end
@@ -720,8 +730,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
draw do
resources :replies do
member do
- put :answer, :to => :mark_as_answer
- delete :answer, :to => :unmark_as_answer
+ put :answer, :action => :mark_as_answer
+ delete :answer, :action => :unmark_as_answer
end
end
end
@@ -1178,7 +1188,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
controller :articles do
scope '/articles', :as => 'article' do
scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
- get '/:id', :to => :with_id, :as => ""
+ get '/:id', :action => :with_id, :as => ""
end
end
end
@@ -1425,7 +1435,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
def test_scoped_controller_with_namespace_and_action
draw do
namespace :account do
- get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback
+ get ':action/callback', :action => /twitter|github/, :controller => "callbacks", :as => :callback
end
end
@@ -1482,7 +1492,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
def test_normalize_namespaced_matches
draw do
namespace :account do
- get 'description', :to => :description, :as => "description"
+ get 'description', :action => :description, :as => "description"
end
end
@@ -1723,7 +1733,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "whatever/:controller(/:action(/:id))"
end
- get 'whatever/foo/bar'
+ get '/whatever/foo/bar'
assert_equal 'foo#bar', @response.body
assert_equal 'http://www.example.com/whatever/foo/bar/1',
@@ -1735,10 +1745,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "whatever/:controller(/:action(/:id))", :id => /\d+/
end
- get 'whatever/foo/bar/show'
+ get '/whatever/foo/bar/show'
assert_equal 'foo/bar#show', @response.body
- get 'whatever/foo/bar/show/1'
+ get '/whatever/foo/bar/show/1'
assert_equal 'foo/bar#show', @response.body
assert_equal 'http://www.example.com/whatever/foo/bar/show',
@@ -2012,6 +2022,28 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/blogs/1/posts/2/comments/new', new_blog_post_comment_path(:blog_id => 1, :post_id => 2)
end
+ def test_direct_children_of_shallow_resources
+ draw do
+ resources :blogs do
+ resources :posts, shallow: true do
+ resources :comments
+ end
+ end
+ end
+
+ post '/posts/1/comments'
+ assert_equal 'comments#create', @response.body
+ assert_equal '/posts/1/comments', post_comments_path('1')
+
+ get '/posts/2/comments/new'
+ assert_equal 'comments#new', @response.body
+ assert_equal '/posts/2/comments/new', new_post_comment_path('2')
+
+ get '/posts/1/comments'
+ assert_equal 'comments#index', @response.body
+ assert_equal '/posts/1/comments', post_comments_path('1')
+ end
+
def test_shallow_nested_resources_within_scope
draw do
scope '/hello' do
@@ -2144,7 +2176,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :invoices do
get "outstanding" => "invoices#outstanding", :on => :collection
- get "overdue", :to => :overdue, :on => :collection
+ get "overdue", :action => :overdue, :on => :collection
get "print" => "invoices#print", :as => :print, :on => :member
post "preview" => "invoices#preview", :as => :preview, :on => :new
end
@@ -2232,6 +2264,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml)
end
+ def test_match_without_via
+ assert_raises(ArgumentError) do
+ draw do
+ match '/foo/bar', :to => 'files#show'
+ end
+ end
+ end
+
+ def test_match_with_empty_via
+ assert_raises(ArgumentError) do
+ draw do
+ match '/foo/bar', :to => 'files#show', :via => []
+ end
+ end
+ end
+
def test_glob_parameter_accepts_regexp
draw do
get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
@@ -2287,12 +2335,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "(/user/:username)/photos" => "photos#index"
end
- get 'user/bob/photos'
+ get '/user/bob/photos'
assert_equal 'photos#index', @response.body
assert_equal 'http://www.example.com/user/bob/photos',
url_for(:controller => "photos", :action => "index", :username => "bob")
- get 'photos'
+ get '/photos'
assert_equal 'photos#index', @response.body
assert_equal 'http://www.example.com/photos',
url_for(:controller => "photos", :action => "index", :username => nil)
@@ -2805,7 +2853,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- def test_symbolized_path_parameters_is_not_stale
+ def test_path_parameters_is_not_stale
draw do
scope '/countries/:country', :constraints => lambda { |params, req| %w(all France).include?(params[:country]) } do
get '/', :to => 'countries#index'
@@ -2970,7 +3018,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
assert_raise(ArgumentError) do
- draw { controller("/feeds") { get '/feeds/:service', :to => :show } }
+ assert_deprecated do
+ draw { controller("/feeds") { get '/feeds/:service', :to => :show } }
+ end
end
assert_raise(ArgumentError) do
@@ -3120,7 +3170,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/downloads/1/1.tar'
assert_equal 'downloads#show', @response.body
- assert_equal expected_params, @request.symbolized_path_parameters
+ assert_equal expected_params, @request.path_parameters
assert_equal '/downloads/1/1.tar', download_path('1')
assert_equal '/downloads/1/1.tar', download_path('1', '1')
end
@@ -3137,6 +3187,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/foo', foo_root_path
end
+ def test_namespace_as_controller
+ draw do
+ namespace :foo do
+ get '/', to: '/bar#index', as: 'root'
+ end
+ end
+
+ get '/foo'
+ assert_equal 'bar#index', @response.body
+ assert_equal '/foo', foo_root_path
+ end
+
def test_trailing_slash
draw do
resources :streams
@@ -3217,6 +3279,58 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/admin/posts/1/comments', admin_post_comments_path('1')
end
+ def test_mix_string_to_controller_action
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_string_to_controller
+ draw do
+ get '/projects', controller: 'project_files',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_string_to_action
+ draw do
+ get '/projects', action: 'index',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_symbol_to_controller_action
+ assert_deprecated do
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: :show
+ end
+ end
+ get '/projects'
+ assert_equal 'project_files#show', @response.body
+ end
+
+ def test_mix_string_to_controller_action_no_hash
+ assert_deprecated do
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: 'show'
+ end
+ end
+ get '/projects'
+ assert_equal 'show#index', @response.body
+ end
+
def test_shallow_path_and_prefix_are_not_added_to_non_shallow_routes
draw do
scope shallow_path: 'projects', shallow_prefix: 'project' do
@@ -3329,19 +3443,19 @@ private
def draw(&block)
self.class.stub_controllers do |routes|
- @app = routes
- @app.default_url_options = { host: 'www.example.com' }
- @app.draw(&block)
+ routes.default_url_options = { host: 'www.example.com' }
+ routes.draw(&block)
+ @app = RoutedRackApp.new routes
end
end
def url_for(options = {})
- @app.url_helpers.url_for(options)
+ @app.routes.url_helpers.url_for(options)
end
def method_missing(method, *args, &block)
if method.to_s =~ /_(path|url)$/
- @app.url_helpers.send(method, *args, &block)
+ @app.routes.url_helpers.send(method, *args, &block)
else
super
end
@@ -3368,12 +3482,14 @@ end
class TestAltApp < ActionDispatch::IntegrationTest
class AltRequest
+ attr_accessor :path_parameters, :path_info, :script_name
+ attr_reader :env
+
def initialize(env)
+ @path_parameters = {}
@env = env
- end
-
- def path_info
- "/"
+ @path_info = "/"
+ @script_name = ""
end
def request_method
@@ -3407,8 +3523,10 @@ class TestAltApp < ActionDispatch::IntegrationTest
get "/" => TestAltApp::AltApp.new
end
+ APP = build_app AltRoutes
+
def app
- AltRoutes
+ APP
end
def test_alt_request_without_header
@@ -3435,15 +3553,16 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest
def setup
super
s = self
- @app = ActionDispatch::Routing::RouteSet.new
- @app.append do
+ routes = ActionDispatch::Routing::RouteSet.new
+ routes.append do
get '/hello' => s.simple_app('fail')
get '/goodbye' => s.simple_app('goodbye')
end
- @app.draw do
+ routes.draw do
get '/hello' => s.simple_app('hello')
end
+ @app = self.class.build_app routes
end
def test_goodbye_should_be_available
@@ -3472,8 +3591,38 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
end
def draw(&block)
- @app = ActionDispatch::Routing::RouteSet.new
- @app.draw(&block)
+ routes = ActionDispatch::Routing::RouteSet.new
+ routes.draw(&block)
+ @app = self.class.build_app routes
+ end
+
+ def test_missing_controller
+ ex = assert_raises(ArgumentError) {
+ draw do
+ get '/foo/bar', :action => :index
+ end
+ }
+ assert_match(/Missing :controller/, ex.message)
+ end
+
+ def test_missing_action
+ ex = assert_raises(ArgumentError) {
+ assert_deprecated do
+ draw do
+ get '/foo/bar', :to => 'foo'
+ end
+ end
+ }
+ assert_match(/Missing :action/, ex.message)
+ end
+
+ def test_missing_action_on_hash
+ ex = assert_raises(ArgumentError) {
+ draw do
+ get '/foo/bar', :to => 'foo#'
+ end
+ }
+ assert_match(/Missing :action/, ex.message)
end
def test_valid_controller_options_inside_namespace
@@ -3492,7 +3641,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
resources :storage_files, :controller => 'admin/storage_files'
end
- get 'storage_files'
+ get '/storage_files'
assert_equal "admin/storage_files#index", @response.body
end
@@ -3517,6 +3666,16 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
assert_match "'Admin::StorageFiles' is not a supported controller name", e.message
end
+
+ def test_warn_with_ruby_constant_syntax_no_colons
+ e = assert_raise(ArgumentError) do
+ draw do
+ resources :storage_files, :controller => 'Admin'
+ end
+ end
+
+ assert_match "'Admin' is not a supported controller name", e.message
+ end
end
class TestDefaultScope < ActionDispatch::IntegrationTest
@@ -3534,8 +3693,10 @@ class TestDefaultScope < ActionDispatch::IntegrationTest
resources :posts
end
+ APP = build_app DefaultScopeRoutes
+
def app
- DefaultScopeRoutes
+ APP
end
include DefaultScopeRoutes.url_helpers
@@ -3560,11 +3721,14 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] }
end
- setup do
+ attr_reader :app
+
+ def setup
s = self
- @app = ActionDispatch::Routing::RouteSet.new
+ routes = ActionDispatch::Routing::RouteSet.new
+ @app = RoutedRackApp.new routes
- @app.draw do
+ routes.draw do
(RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method|
match '/' => s.simple_app(method), :via => method.underscore.to_sym
end
@@ -3595,7 +3759,8 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test 'escapes slash in generated path segment' do
assert_equal '/a%20b%2Fc+d', segment_path(:segment => 'a b/c+d')
@@ -3626,7 +3791,8 @@ class TestUnicodePaths < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test 'recognizes unicode path' do
get "/#{Rack::Utils.escape("ほげ")}"
@@ -3657,7 +3823,8 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test "controller option which starts with '/' from multiple nested controller" do
get "/foo/bar/baz"
@@ -3676,7 +3843,8 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test 'recognizes tilde path' do
get "/~user"
@@ -3703,7 +3871,8 @@ class TestRedirectInterpolation < ActionDispatch::IntegrationTest
end
end
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test "redirect escapes interpolated parameters with redirect proc" do
get "/foo/1%3E"
@@ -3745,7 +3914,8 @@ class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest
end
end
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test "parameters are reset between constraint checks" do
get "/bar"
@@ -3765,7 +3935,8 @@ class TestGlobRoutingMapper < ActionDispatch::IntegrationTest
end
#include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
def test_glob_constraint
get "/dummy"
@@ -3797,7 +3968,8 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test 'enabled when not mounted and default_url_options is empty' do
assert Routes.url_helpers.optimize_routes_generation?
@@ -3869,7 +4041,8 @@ class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest
end
end
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
include Routes.url_helpers
@@ -3904,7 +4077,8 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
test "constraints are copied to defaults when using constraints method" do
assert_equal 'http://admin.example.com/', admin_root_url
@@ -3958,7 +4132,7 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
set.draw do
get "/bar/:id", :to => redirect("/foo/show/%{id}")
get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
- get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo"
+ get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo"
get "/:controller(/:action(/:id))"
end
@@ -3985,8 +4159,9 @@ class TestOptionalRootSegments < ActionDispatch::IntegrationTest
end
end
+ APP = build_app Routes
def app
- Routes
+ APP
end
include Routes.url_helpers
@@ -4017,7 +4192,8 @@ class TestPortConstraints < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
def test_integer_port_constraints
get 'http://www.example.com/integer'
@@ -4065,7 +4241,8 @@ class TestFormatConstraints < ActionDispatch::IntegrationTest
end
include Routes.url_helpers
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
def test_string_format_constraints
get 'http://www.example.com/string'
@@ -4134,8 +4311,9 @@ class TestRouteDefaults < ActionDispatch::IntegrationTest
end
end
+ APP = build_app Routes
def app
- Routes
+ APP
end
include Routes.url_helpers
@@ -4163,8 +4341,9 @@ class TestRackAppRouteGeneration < ActionDispatch::IntegrationTest
end
end
+ APP = build_app Routes
def app
- Routes
+ APP
end
include Routes.url_helpers
@@ -4189,8 +4368,9 @@ class TestRedirectRouteGeneration < ActionDispatch::IntegrationTest
end
end
+ APP = build_app Routes
def app
- Routes
+ APP
end
include Routes.url_helpers
@@ -4213,7 +4393,8 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
end
end
- def app; Routes end
+ APP = build_app Routes
+ def app; APP end
include Routes.url_helpers
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 92544230b2..f7a06cfed4 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -49,6 +49,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: "bar"', response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_nil_session_value
@@ -57,6 +59,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: nil', response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_session_value_after_session_reset
@@ -76,6 +80,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_from_nonexistent_session
@@ -85,6 +91,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_equal 'foo: nil', response.body
assert_nil cookies['_session_id'], "should only create session on write, not read"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_setting_session_value_after_session_reset
@@ -106,6 +114,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_not_equal session_id, response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_session_id
@@ -119,6 +129,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_deserializes_unloaded_class
@@ -133,6 +145,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
end
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_doesnt_write_session_cookie_if_session_id_is_already_exists
@@ -145,6 +159,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_prevents_session_fixation
@@ -160,6 +176,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_not_equal session_id, cookies['_session_id']
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
rescue LoadError, RuntimeError, Dalli::DalliError
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb
index 910ff8a80f..8f79e7bf9a 100644
--- a/actionpack/test/dispatch/url_generation_test.rb
+++ b/actionpack/test/dispatch/url_generation_test.rb
@@ -15,15 +15,19 @@ module TestUrlGeneration
Routes.draw do
get "/foo", :to => "my_route_generating#index", :as => :foo
+ resources :bars
+
mount MyRouteGeneratingController.action(:index), at: '/bar'
end
+ APP = build_app Routes
+
def _routes
Routes
end
def app
- Routes
+ APP
end
test "generating URLS normally" do
@@ -109,6 +113,22 @@ module TestUrlGeneration
test "omit subdomain when key is blank" do
assert_equal "http://example.com/foo", foo_url(subdomain: "")
end
+
+ test "generating URLs with trailing slashes" do
+ assert_equal "/bars.json", bars_path(
+ trailing_slash: true,
+ format: 'json'
+ )
+ end
+
+ test "generating URLS with querystring and trailing slashes" do
+ assert_equal "/bars.json?a=b", bars_path(
+ trailing_slash: true,
+ a: 'b',
+ format: 'json'
+ )
+ end
+
end
end
diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb
index ce02104181..9dfdfc23ed 100644
--- a/actionpack/test/journey/path/pattern_test.rb
+++ b/actionpack/test/journey/path/pattern_test.rb
@@ -18,7 +18,7 @@ module ActionDispatch
'/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar\Z},
}.each do |path, expected|
define_method(:"test_to_regexp_#{path}") do
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
path,
{ :controller => /.+/ },
["/", ".", "?"]
@@ -41,7 +41,7 @@ module ActionDispatch
'/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar},
}.each do |path, expected|
define_method(:"test_to_non_anchored_regexp_#{path}") do
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
path,
{ :controller => /.+/ },
["/", ".", "?"],
@@ -65,7 +65,7 @@ module ActionDispatch
'/:controller/*foo/bar' => %w{ controller foo },
}.each do |path, expected|
define_method(:"test_names_#{path}") do
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
path,
{ :controller => /.+/ },
["/", ".", "?"]
@@ -75,12 +75,8 @@ module ActionDispatch
end
end
- def test_to_raise_exception_with_bad_expression
- assert_raise(ArgumentError, "Bad expression: []") { Pattern.new [] }
- end
-
def test_to_regexp_with_extended_group
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name',
{ :name => /
#ROFL
@@ -101,13 +97,13 @@ module ActionDispatch
['/:foo(/:bar)', %w{ bar }],
['/:foo(/:bar)/:lol(/:baz)', %w{ bar baz }],
].each do |pattern, list|
- path = Pattern.new pattern
+ path = Pattern.from_string pattern
assert_equal list.sort, path.optional_names.sort
end
end
def test_to_regexp_match_non_optional
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/:name',
{ :name => /\d+/ },
["/", ".", "?"]
@@ -118,7 +114,7 @@ module ActionDispatch
end
def test_to_regexp_with_group
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name',
{ :name => /(tender|love)/ },
["/", ".", "?"]
@@ -131,7 +127,7 @@ module ActionDispatch
def test_ast_sets_regular_expressions
requirements = { :name => /(tender|love)/, :value => /./ }
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name/:value',
requirements,
["/", ".", "?"]
@@ -148,7 +144,7 @@ module ActionDispatch
end
def test_match_data_with_group
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name',
{ :name => /(tender|love)/ },
["/", ".", "?"]
@@ -160,7 +156,7 @@ module ActionDispatch
end
def test_match_data_with_multi_group
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name/:id',
{ :name => /t(((ender|love)))()/ },
["/", ".", "?"]
@@ -175,7 +171,7 @@ module ActionDispatch
def test_star_with_custom_re
z = /\d+/
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/*foo',
{ :foo => z },
["/", ".", "?"]
@@ -185,7 +181,7 @@ module ActionDispatch
end
def test_insensitive_regexp_with_group
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
'/page/:name/aaron',
{ :name => /(tender|love)/i },
["/", ".", "?"]
@@ -197,7 +193,7 @@ module ActionDispatch
end
def test_to_regexp_with_strexp
- strexp = Router::Strexp.new('/:controller', { }, ["/", ".", "?"])
+ strexp = Router::Strexp.build('/:controller', { }, ["/", ".", "?"])
path = Pattern.new strexp
x = %r{\A/([^/.?]+)\Z}
@@ -205,20 +201,20 @@ module ActionDispatch
end
def test_to_regexp_defaults
- path = Pattern.new '/:controller(/:action(/:id))'
+ path = Pattern.from_string '/:controller(/:action(/:id))'
expected = %r{\A/([^/.?]+)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z}
assert_equal expected, path.to_regexp
end
def test_failed_match
- path = Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Pattern.from_string '/:controller(/:action(/:id(.:format)))'
uri = 'content'
assert_not path =~ uri
end
def test_match_controller
- path = Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Pattern.from_string '/:controller(/:action(/:id(.:format)))'
uri = '/content'
match = path =~ uri
@@ -230,7 +226,7 @@ module ActionDispatch
end
def test_match_controller_action
- path = Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Pattern.from_string '/:controller(/:action(/:id(.:format)))'
uri = '/content/list'
match = path =~ uri
@@ -242,7 +238,7 @@ module ActionDispatch
end
def test_match_controller_action_id
- path = Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Pattern.from_string '/:controller(/:action(/:id(.:format)))'
uri = '/content/list/10'
match = path =~ uri
@@ -254,7 +250,7 @@ module ActionDispatch
end
def test_match_literal
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
uri = '/books'
match = path =~ uri
@@ -264,7 +260,7 @@ module ActionDispatch
end
def test_match_literal_with_action
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
uri = '/books/list'
match = path =~ uri
@@ -274,7 +270,7 @@ module ActionDispatch
end
def test_match_literal_with_action_and_format
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
uri = '/books/list.rss'
match = path =~ uri
diff --git a/actionpack/test/journey/route_test.rb b/actionpack/test/journey/route_test.rb
index cbe6284714..21d867aca0 100644
--- a/actionpack/test/journey/route_test.rb
+++ b/actionpack/test/journey/route_test.rb
@@ -5,7 +5,7 @@ module ActionDispatch
class TestRoute < ActiveSupport::TestCase
def test_initialize
app = Object.new
- path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))'
defaults = {}
route = Route.new("name", app, path, {}, defaults)
@@ -16,7 +16,7 @@ module ActionDispatch
def test_route_adds_itself_as_memo
app = Object.new
- path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))'
defaults = {}
route = Route.new("name", app, path, {}, defaults)
@@ -26,21 +26,21 @@ module ActionDispatch
end
def test_ip_address
- path = Path::Pattern.new '/messages/:id(.:format)'
+ path = Path::Pattern.from_string '/messages/:id(.:format)'
route = Route.new("name", nil, path, {:ip => '192.168.1.1'},
{ :controller => 'foo', :action => 'bar' })
assert_equal '192.168.1.1', route.ip
end
def test_default_ip
- path = Path::Pattern.new '/messages/:id(.:format)'
+ path = Path::Pattern.from_string '/messages/:id(.:format)'
route = Route.new("name", nil, path, {},
{ :controller => 'foo', :action => 'bar' })
assert_equal(//, route.ip)
end
def test_format_with_star
- path = Path::Pattern.new '/:controller/*extra'
+ path = Path::Pattern.from_string '/:controller/*extra'
route = Route.new("name", nil, path, {},
{ :controller => 'foo', :action => 'bar' })
assert_equal '/foo/himom', route.format({
@@ -50,7 +50,7 @@ module ActionDispatch
end
def test_connects_all_match
- path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))'
+ path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))'
route = Route.new("name", nil, path, {:action => 'bar'}, { :controller => 'foo' })
assert_equal '/foo/bar/10', route.format({
@@ -61,21 +61,21 @@ module ActionDispatch
end
def test_extras_are_not_included_if_optional
- path = Path::Pattern.new '/page/:id(/:action)'
+ path = Path::Pattern.from_string '/page/:id(/:action)'
route = Route.new("name", nil, path, { }, { :action => 'show' })
assert_equal '/page/10', route.format({ :id => 10 })
end
def test_extras_are_not_included_if_optional_with_parameter
- path = Path::Pattern.new '(/sections/:section)/pages/:id'
+ path = Path::Pattern.from_string '(/sections/:section)/pages/:id'
route = Route.new("name", nil, path, { }, { :action => 'show' })
assert_equal '/pages/10', route.format({:id => 10})
end
def test_extras_are_not_included_if_optional_parameter_is_nil
- path = Path::Pattern.new '(/sections/:section)/pages/:id'
+ path = Path::Pattern.from_string '(/sections/:section)/pages/:id'
route = Route.new("name", nil, path, { }, { :action => 'show' })
assert_equal '/pages/10', route.format({:id => 10, :section => nil})
@@ -85,10 +85,10 @@ module ActionDispatch
constraints = {:required_defaults => [:controller, :action]}
defaults = {:controller=>"pages", :action=>"show"}
- path = Path::Pattern.new "/page/:id(/:action)(.:format)"
+ path = Path::Pattern.from_string "/page/:id(/:action)(.:format)"
specific = Route.new "name", nil, path, constraints, defaults
- path = Path::Pattern.new "/:controller(/:action(/:id))(.:format)"
+ path = Path::Pattern.from_string "/:controller(/:action(/:id))(.:format)"
generic = Route.new "name", nil, path, constraints
knowledge = {:id=>20, :controller=>"pages", :action=>"show"}
diff --git a/actionpack/test/journey/router/strexp_test.rb b/actionpack/test/journey/router/strexp_test.rb
deleted file mode 100644
index 7ccdfb7b4d..0000000000
--- a/actionpack/test/journey/router/strexp_test.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'abstract_unit'
-
-module ActionDispatch
- module Journey
- class Router
- class TestStrexp < ActiveSupport::TestCase
- def test_many_names
- exp = Strexp.new(
- "/:controller(/:action(/:id(.:format)))",
- {:controller=>/.+?/},
- ["/", ".", "?"],
- true)
-
- assert_equal ["controller", "action", "id", "format"], exp.names
- end
-
- def test_names
- {
- "/bar(.:format)" => %w{ format },
- ":format" => %w{ format },
- ":format-" => %w{ format },
- ":format0" => %w{ format0 },
- ":format1,:format2" => %w{ format1 format2 },
- }.each do |string, expected|
- exp = Strexp.new(string, {}, ["/", ".", "?"])
- assert_equal expected, exp.names
- end
- end
- end
- end
- end
-end
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index e54b64e0f3..2e7e8e1bea 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -4,24 +4,15 @@ require 'abstract_unit'
module ActionDispatch
module Journey
class TestRouter < ActiveSupport::TestCase
- # TODO : clean up routing tests so we don't need this hack
- class StubDispatcher < Routing::RouteSet::Dispatcher; end
-
attr_reader :routes
def setup
- @app = StubDispatcher.new
+ @app = Routing::RouteSet::Dispatcher.new({})
@routes = Routes.new
- @router = Router.new(@routes, {})
+ @router = Router.new(@routes)
@formatter = Formatter.new(@routes)
end
- def test_request_class_reader
- klass = Object.new
- router = Router.new(routes, :request_class => klass)
- assert_equal klass, router.request_class
- end
-
class FakeRequestFeeler < Struct.new(:env, :called)
def new env
self.env = env
@@ -39,33 +30,33 @@ module ActionDispatch
end
def test_dashes
- router = Router.new(routes, {})
+ router = Router.new(routes)
- exp = Router::Strexp.new '/foo-bar-baz', {}, ['/.?']
+ exp = Router::Strexp.build '/foo-bar-baz', {}, ['/.?']
path = Path::Pattern.new exp
routes.add_route nil, path, {}, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/foo-bar-baz'
called = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
called = true
end
assert called
end
def test_unicode
- router = Router.new(routes, {})
+ router = Router.new(routes)
#match the escaped version of /ほげ
- exp = Router::Strexp.new '/%E3%81%BB%E3%81%92', {}, ['/.?']
+ exp = Router::Strexp.build '/%E3%81%BB%E3%81%92', {}, ['/.?']
path = Path::Pattern.new exp
routes.add_route nil, path, {}, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/%E3%81%BB%E3%81%92'
called = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
called = true
end
assert called
@@ -73,17 +64,17 @@ module ActionDispatch
def test_request_class_and_requirements_success
klass = FakeRequestFeeler.new nil
- router = Router.new(routes, {:request_class => klass })
+ router = Router.new(routes)
requirements = { :hello => /world/ }
- exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
+ exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?']
path = Path::Pattern.new exp
routes.add_route nil, path, requirements, {:id => nil}, {}
- env = rails_env 'PATH_INFO' => '/foo/10'
- router.recognize(env) do |r, _, params|
+ env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
+ router.recognize(env) do |r, params|
assert_equal({:id => '10'}, params)
end
@@ -93,17 +84,17 @@ module ActionDispatch
def test_request_class_and_requirements_fail
klass = FakeRequestFeeler.new nil
- router = Router.new(routes, {:request_class => klass })
+ router = Router.new(routes)
requirements = { :hello => /mom/ }
- exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
+ exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?']
path = Path::Pattern.new exp
router.routes.add_route nil, path, requirements, {:id => nil}, {}
- env = rails_env 'PATH_INFO' => '/foo/10'
- router.recognize(env) do |r, _, params|
+ env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
+ router.recognize(env) do |r, params|
flunk 'route should not be found'
end
@@ -111,24 +102,29 @@ module ActionDispatch
assert_equal env.env, klass.env
end
- class CustomPathRequest < Router::NullReq
+ class CustomPathRequest < ActionDispatch::Request
def path_info
env['custom.path_info']
end
+
+ def path_info=(x)
+ env['custom.path_info'] = x
+ end
end
def test_request_class_overrides_path_info
- router = Router.new(routes, {:request_class => CustomPathRequest })
+ router = Router.new(routes)
- exp = Router::Strexp.new '/bar', {}, ['/.?']
+ exp = Router::Strexp.build '/bar', {}, ['/.?']
path = Path::Pattern.new exp
routes.add_route nil, path, {}, {}, {}
- env = rails_env 'PATH_INFO' => '/foo', 'custom.path_info' => '/bar'
+ env = rails_env({'PATH_INFO' => '/foo',
+ 'custom.path_info' => '/bar'}, CustomPathRequest)
recognized = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
recognized = true
end
@@ -137,14 +133,14 @@ module ActionDispatch
def test_regexp_first_precedence
add_routes @router, [
- Router::Strexp.new("/whois/:domain", {:domain => /\w+\.[\w\.]+/}, ['/', '.', '?']),
- Router::Strexp.new("/whois/:id(.:format)", {}, ['/', '.', '?'])
+ Router::Strexp.build("/whois/:domain", {:domain => /\w+\.[\w\.]+/}, ['/', '.', '?']),
+ Router::Strexp.build("/whois/:id(.:format)", {}, ['/', '.', '?'])
]
env = rails_env 'PATH_INFO' => '/whois/example.com'
list = []
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
list << r
end
assert_equal 2, list.length
@@ -156,50 +152,50 @@ module ActionDispatch
def test_required_parts_verified_are_anchored
add_routes @router, [
- Router::Strexp.new("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false)
+ Router::Strexp.build("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false)
]
assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ @formatter.generate(nil, { :id => '10' }, { })
end
end
def test_required_parts_are_verified_when_building
add_routes @router, [
- Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
+ Router::Strexp.build("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
]
- path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :id => '10' }, { })
assert_equal '/foo/10', path
assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
+ @formatter.generate(nil, { :id => 'aa' }, { })
end
end
def test_only_required_parts_are_verified
add_routes @router, [
- Router::Strexp.new("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false)
+ Router::Strexp.build("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false)
]
- path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :id => '10' }, { })
assert_equal '/foo/10', path
- path, _ = @formatter.generate(:path_info, nil, { }, { })
+ path, _ = @formatter.generate(nil, { }, { })
assert_equal '/foo', path
- path, _ = @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
+ path, _ = @formatter.generate(nil, { :id => 'aa' }, { })
assert_equal '/foo/aa', path
end
def test_knows_what_parts_are_missing_from_named_route
route_name = "gorby_thunderhorse"
- pattern = Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
+ pattern = Router::Strexp.build("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
path = Path::Pattern.new pattern
@router.routes.add_route nil, path, {}, {}, route_name
error = assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, route_name, { }, { })
+ @formatter.generate(route_name, { }, { })
end
assert_match(/missing required keys: \[:id\]/, error.message)
@@ -207,42 +203,43 @@ module ActionDispatch
def test_X_Cascade
add_routes @router, [ "/messages(.:format)" ]
- resp = @router.call({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' })
+ resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }))
assert_equal ['Not Found'], resp.last
assert_equal 'pass', resp[1]['X-Cascade']
assert_equal 404, resp.first
end
def test_clear_trailing_slash_from_script_name_on_root_unanchored_routes
- strexp = Router::Strexp.new("/", {}, ['/', '.', '?'], false)
- path = Path::Pattern.new strexp
+ route_set = Routing::RouteSet.new
+ mapper = Routing::Mapper.new route_set
+
app = lambda { |env| [200, {}, ['success!']] }
- @router.routes.add_route(app, path, {}, {}, {})
+ mapper.get '/weblog', :to => app
env = rack_env('SCRIPT_NAME' => '', 'PATH_INFO' => '/weblog')
- resp = @router.call(env)
+ resp = route_set.call env
assert_equal ['success!'], resp.last
assert_equal '', env['SCRIPT_NAME']
end
def test_defaults_merge_correctly
- path = Path::Pattern.new '/foo(/:id)'
+ path = Path::Pattern.from_string '/foo(/:id)'
@router.routes.add_route nil, path, {}, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/foo/10'
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal({:id => '10'}, params)
end
env = rails_env 'PATH_INFO' => '/foo'
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal({:id => nil}, params)
end
end
def test_recognize_with_unbound_regexp
add_routes @router, [
- Router::Strexp.new("/foo", { }, ['/', '.', '?'], false)
+ Router::Strexp.build("/foo", { }, ['/', '.', '?'], false)
]
env = rails_env 'PATH_INFO' => '/foo/bar'
@@ -255,7 +252,7 @@ module ActionDispatch
def test_bound_regexp_keeps_path_info
add_routes @router, [
- Router::Strexp.new("/foo", { }, ['/', '.', '?'], true)
+ Router::Strexp.build("/foo", { }, ['/', '.', '?'], true)
]
env = rails_env 'PATH_INFO' => '/foo'
@@ -287,14 +284,14 @@ module ActionDispatch
def test_required_part_in_recall
add_routes @router, [ "/messages/:a/:b" ]
- path, _ = @formatter.generate(:path_info, nil, { :a => 'a' }, { :b => 'b' })
+ path, _ = @formatter.generate(nil, { :a => 'a' }, { :b => 'b' })
assert_equal "/messages/a/b", path
end
def test_splat_in_recall
add_routes @router, [ "/*path" ]
- path, _ = @formatter.generate(:path_info, nil, { }, { :path => 'b' })
+ path, _ = @formatter.generate(nil, { }, { :path => 'b' })
assert_equal "/b", path
end
@@ -304,35 +301,35 @@ module ActionDispatch
"/messages/:id(.:format)"
]
- path, _ = @formatter.generate(:path_info, nil, { :id => 10 }, { :action => 'index' })
+ path, _ = @formatter.generate(nil, { :id => 10 }, { :action => 'index' })
assert_equal "/messages/index/10", path
end
def test_nil_path_parts_are_ignored
- path = Path::Pattern.new "/:controller(/:action(.:format))"
+ path = Path::Pattern.from_string "/:controller(/:action(.:format))"
@router.routes.add_route @app, path, {}, {}, {}
params = { :controller => "tasks", :format => nil }
extras = { :action => 'lol' }
- path, _ = @formatter.generate(:path_info, nil, params, extras)
+ path, _ = @formatter.generate(nil, params, extras)
assert_equal '/tasks', path
end
def test_generate_slash
params = [ [:controller, "tasks"],
[:action, "show"] ]
- str = Router::Strexp.new("/", Hash[params], ['/', '.', '?'], true)
+ str = Router::Strexp.build("/", Hash[params], ['/', '.', '?'], true)
path = Path::Pattern.new str
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info, nil, Hash[params], {})
+ path, _ = @formatter.generate(nil, Hash[params], {})
assert_equal '/', path
end
def test_generate_calls_param_proc
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
parameterized = []
@@ -340,7 +337,6 @@ module ActionDispatch
[:action, "show"] ]
@formatter.generate(
- :path_info,
nil,
Hash[params],
{},
@@ -350,31 +346,31 @@ module ActionDispatch
end
def test_generate_id
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
path, params = @formatter.generate(
- :path_info, nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
+ nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
assert_equal '/tasks/show', path
assert_equal({:id => 1}, params)
end
def test_generate_escapes
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info,
- nil, { :controller => "tasks",
+ path, _ = @formatter.generate(nil,
+ { :controller => "tasks",
:action => "a/b c+d",
}, {})
assert_equal '/tasks/a%2Fb%20c+d', path
end
def test_generate_escapes_with_namespaced_controller
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info,
+ path, _ = @formatter.generate(
nil, { :controller => "admin/tasks",
:action => "a/b c+d",
}, {})
@@ -382,10 +378,10 @@ module ActionDispatch
end
def test_generate_extra_params
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
nil, { :id => 1,
:controller => "tasks",
:action => "show",
@@ -396,10 +392,10 @@ module ActionDispatch
end
def test_generate_uses_recall_if_needed
- path = Path::Pattern.new '/:controller(/:action(/:id))'
+ path = Path::Pattern.from_string '/:controller(/:action(/:id))'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
nil,
{:controller =>"tasks", :id => 10},
{:action =>"index"})
@@ -408,10 +404,10 @@ module ActionDispatch
end
def test_generate_with_name
- path = Path::Pattern.new '/:controller(/:action)'
+ path = Path::Pattern.from_string '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
"tasks",
{:controller=>"tasks"},
{:controller=>"tasks", :action=>"index"})
@@ -425,14 +421,14 @@ module ActionDispatch
'/content/show/10' => { :controller => 'content', :action => 'show', :id => "10" },
}.each do |request_path, expected|
define_method("test_recognize_#{expected.keys.map(&:to_s).join('_')}") do
- path = Path::Pattern.new "/:controller(/:action(/:id))"
+ path = Path::Pattern.from_string "/:controller(/:action(/:id))"
app = Object.new
route = @router.routes.add_route(app, path, {}, {}, {})
env = rails_env 'PATH_INFO' => request_path
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -447,14 +443,14 @@ module ActionDispatch
:splat => ['/segment/a/b%20c+d', { :segment => 'segment', :splat => 'a/b c+d' }]
}.each do |name, (request_path, expected)|
define_method("test_recognize_#{name}") do
- path = Path::Pattern.new '/:segment/*splat'
+ path = Path::Pattern.from_string '/:segment/*splat'
app = Object.new
route = @router.routes.add_route(app, path, {}, {}, {})
env = rails_env 'PATH_INFO' => request_path
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -465,7 +461,7 @@ module ActionDispatch
end
def test_namespaced_controller
- strexp = Router::Strexp.new(
+ strexp = Router::Strexp.build(
"/:controller(/:action(/:id))",
{ :controller => /.+?/ },
["/", ".", "?"]
@@ -482,7 +478,7 @@ module ActionDispatch
:id => '10'
}
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -491,14 +487,14 @@ module ActionDispatch
end
def test_recognize_literal
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
app = Object.new
route = @router.routes.add_route(app, path, {}, {:controller => 'books'})
env = rails_env 'PATH_INFO' => '/books/list.rss'
expected = { :controller => 'books', :action => 'list', :format => 'rss' }
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -508,7 +504,7 @@ module ActionDispatch
end
def test_recognize_head_request_as_get_route
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
app = Object.new
conditions = {
:request_method => 'GET'
@@ -519,7 +515,7 @@ module ActionDispatch
"REQUEST_METHOD" => "HEAD"
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
called = true
end
@@ -527,7 +523,7 @@ module ActionDispatch
end
def test_recognize_cares_about_verbs
- path = Path::Pattern.new "/books(/:action(.:format))"
+ path = Path::Pattern.from_string "/books(/:action(.:format))"
app = Object.new
conditions = {
:request_method => 'GET'
@@ -543,7 +539,7 @@ module ActionDispatch
"REQUEST_METHOD" => "POST"
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal post, r
called = true
end
@@ -555,15 +551,17 @@ module ActionDispatch
def add_routes router, paths
paths.each do |path|
- path = Path::Pattern.new path
+ if String === path
+ path = Path::Pattern.from_string path
+ else
+ path = Path::Pattern.new path
+ end
router.routes.add_route @app, path, {}, {}, {}
end
end
- RailsEnv = Struct.new(:env)
-
- def rails_env env
- RailsEnv.new rack_env env
+ def rails_env env, klass = ActionDispatch::Request
+ klass.new env
end
def rack_env env
diff --git a/actionpack/test/journey/routes_test.rb b/actionpack/test/journey/routes_test.rb
index 25e0321d31..a4efc82b8c 100644
--- a/actionpack/test/journey/routes_test.rb
+++ b/actionpack/test/journey/routes_test.rb
@@ -5,7 +5,7 @@ module ActionDispatch
class TestRoutes < ActiveSupport::TestCase
def test_clear
routes = Routes.new
- exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
+ exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?']
path = Path::Pattern.new exp
requirements = { :hello => /world/ }
@@ -18,7 +18,7 @@ module ActionDispatch
def test_ast
routes = Routes.new
- path = Path::Pattern.new '/hello'
+ path = Path::Pattern.from_string '/hello'
routes.add_route nil, path, {}, {}, {}
ast = routes.ast
@@ -28,7 +28,7 @@ module ActionDispatch
def test_simulator_changes
routes = Routes.new
- path = Path::Pattern.new '/hello'
+ path = Path::Pattern.from_string '/hello'
routes.add_route nil, path, {}, {}, {}
sim = routes.simulator
@@ -40,8 +40,8 @@ module ActionDispatch
#def add_route app, path, conditions, defaults, name = nil
routes = Routes.new
- one = Path::Pattern.new '/hello'
- two = Path::Pattern.new '/aaron'
+ one = Path::Pattern.from_string '/hello'
+ two = Path::Pattern.from_string '/aaron'
routes.add_route nil, one, {}, {}, 'aaron'
routes.add_route nil, two, {}, {}, 'aaron'