aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md371
-rw-r--r--actionpack/RUNNING_UNIT_TESTS.rdoc17
-rw-r--r--actionpack/Rakefile1
-rw-r--r--actionpack/actionpack.gemspec8
-rw-r--r--actionpack/lib/abstract_controller/base.rb2
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb12
-rw-r--r--actionpack/lib/action_controller.rb1
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb10
-rw-r--r--actionpack/lib/action_controller/metal.rb6
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb12
-rw-r--r--actionpack/lib/action_controller/metal/etag_with_template_digest.rb4
-rw-r--r--actionpack/lib/action_controller/metal/exceptions.rb2
-rw-r--r--actionpack/lib/action_controller/metal/head.rb4
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb23
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/live.rb8
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb24
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb6
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb3
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb5
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb23
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb6
-rw-r--r--actionpack/lib/action_controller/model_naming.rb12
-rw-r--r--actionpack/lib/action_controller/test_case.rb26
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb3
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb20
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb28
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb113
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb17
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/transition_table.rb47
-rw-r--r--actionpack/lib/action_dispatch/journey/path/pattern.rb9
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb8
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/scanner.rb10
-rw-r--r--actionpack/lib/action_dispatch/journey/visualizer/fsm.css4
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb22
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb80
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb61
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb14
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb16
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb40
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/request/utils.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb46
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb19
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb82
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb92
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb2
-rw-r--r--actionpack/lib/action_pack/gem_version.rb6
-rw-r--r--actionpack/test/abstract_unit.rb8
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb7
-rw-r--r--actionpack/test/controller/filters_test.rb28
-rw-r--r--actionpack/test/controller/flash_hash_test.rb9
-rw-r--r--actionpack/test/controller/helper_test.rb22
-rw-r--r--actionpack/test/controller/http_token_authentication_test.rb23
-rw-r--r--actionpack/test/controller/integration_test.rb44
-rw-r--r--actionpack/test/controller/localized_templates_test.rb4
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb4
-rw-r--r--actionpack/test/controller/new_base/render_file_test.rb29
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb9
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb6
-rw-r--r--actionpack/test/controller/resources_test.rb12
-rw-r--r--actionpack/test/controller/routing_test.rb13
-rw-r--r--actionpack/test/controller/test_case_test.rb87
-rw-r--r--actionpack/test/controller/url_for_test.rb26
-rw-r--r--actionpack/test/controller/webservice_test.rb10
-rw-r--r--actionpack/test/dispatch/cookies_test.rb25
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb92
-rw-r--r--actionpack/test/dispatch/exception_wrapper_test.rb97
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb6
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request_test.rb33
-rw-r--r--actionpack/test/dispatch/response_test.rb34
-rw-r--r--actionpack/test/dispatch/routing/inspector_test.rb44
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb112
-rw-r--r--actionpack/test/dispatch/routing_test.rb30
-rw-r--r--actionpack/test/dispatch/static_test.rb22
-rw-r--r--actionpack/test/dispatch/template_assertions_test.rb14
-rw-r--r--actionpack/test/dispatch/test_request_test.rb2
-rw-r--r--actionpack/test/fixtures/helpers_typo/admin/users_helper.rb5
-rw-r--r--actionpack/test/fixtures/localized/hello_world.de.html2
-rw-r--r--actionpack/test/journey/path/pattern_test.rb2
-rw-r--r--actionpack/test/journey/route/definition/scanner_test.rb25
-rw-r--r--actionpack/test/journey/router_test.rb12
-rw-r--r--actionpack/test/lib/controller/fake_models.rb45
104 files changed, 1464 insertions, 889 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index e250450a76..b5380a46e8 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,363 +1,38 @@
-* Don't rescue `IPAddr::InvalidAddressError`.
+* Using `head` method returns empty response_body instead
+ of returning a single space " ".
- `IPAddr::InvalidAddressError` does not exist in Ruby 1.9.3
- and fails for JRuby in 1.9 mode.
+ The old behavior was added as a workaround for a bug in an early
+ version of Safari, where the HTTP headers are not returned correctly
+ if the response body has a 0-length. This is been fixed since and
+ the workaround is no longer necessary.
- *Peter Suschlik*
+ Fixes #18253.
-* Fix bug where the router would ignore any constraints added to redirect
- routes.
+ *Prathamesh Sonpatki*
- Fixes #16605.
+* Fix how polymorphic routes works with objects that implement `to_model`.
- *Agis Anastasopoulos*
+ *Travis Grathwell*
-* Allow `config.action_dispatch.trusted_proxies` to accept an IPAddr object.
+* Stop converting empty arrays in `params` to `nil`
- Example:
+ This behaviour was introduced in response to CVE-2012-2660, CVE-2012-2694
+ and CVE-2013-0155
- # config/environments/production.rb
- config.action_dispatch.trusted_proxies = IPAddr.new('4.8.15.0/16')
+ ActiveRecord now issues a safe query when passing an empty array into
+ a where clause, so there is no longer a need to defend against this type
+ of input (any nils are still stripped from the array).
- *Sam Aarons*
+ *Chris Sinjakli*
-* Avoid duplicating routes for HEAD requests.
+* Fixed usage of optional scopes in url helpers.
- Instead of duplicating the routes, we will first match the HEAD request to
- HEAD routes. If no match is found, we will then map the HEAD request to
- GET routes.
+ *Alex Robbin*
- *Guo Xiang Tan*, *Andrew White*
+* Fixed handling of positional url helper arguments when `format: false`.
-* Requests that hit `ActionDispatch::Static` can now take advantage
- of gzipped assets on disk. By default a gzip asset will be served if
- the client supports gzip and a compressed file is on disk.
+ Fixes #17819.
- *Richard Schneeman*
+ *Andrew White*, *Tatiana Soukiassian*
-* `ActionController::Parameters` will stop inheriting from `Hash` and
- `HashWithIndifferentAccess` in the next major release. If you use any method
- that is not available on `ActionController::Parameters` you should consider
- calling `#to_h` to convert it to a `Hash` first before calling that method.
-
- *Prem Sichanugrist*
-
-* `ActionController::Parameters#to_h` now returns a `Hash` with unpermitted
- keys removed. This change is to reflect on a security concern where some
- method performed on an `ActionController::Parameters` may yield a `Hash`
- object which does not maintain `permitted?` status. If you would like to
- get a `Hash` with all the keys intact, duplicate and mark it as permitted
- before calling `#to_h`.
-
- params = ActionController::Parameters.new({
- name: 'Senjougahara Hitagi',
- oddity: 'Heavy stone crab'
- })
- params.to_h
- # => {}
-
- unsafe_params = params.dup.permit!
- unsafe_params.to_h
- # => {"name"=>"Senjougahara Hitagi", "oddity"=>"Heavy stone crab"}
-
- safe_params = params.permit(:name)
- safe_params.to_h
- # => {"name"=>"Senjougahara Hitagi"}
-
- This change is consider a stopgap as we cannot change the code to stop
- `ActionController::Parameters` to inherit from `HashWithIndifferentAccess`
- in the next minor release.
-
- *Prem Sichanugrist*
-
-* Deprecated `TagAssertions`.
-
- *Kasper Timm Hansen*
-
-* Use the Active Support JSON encoder for cookie jars using the `:json` or
- `:hybrid` serializer. This allows you to serialize custom Ruby objects into
- cookies by defining the `#as_json` hook on such objects.
-
- Fixes #16520.
-
- *Godfrey Chan*
-
-* Add `config.action_dispatch.cookies_digest` option for setting custom
- digest. The default remains the same - 'SHA1'.
-
- *Łukasz Strzałkowski*
-
-* Move `respond_with` (and the class-level `respond_to`) to
- the `responders` gem.
-
- *José Valim*
-
-* When your templates change, browser caches bust automatically.
-
- New default: the template digest is automatically included in your ETags.
- When you call `fresh_when @post`, the digest for `posts/show.html.erb`
- is mixed in so future changes to the HTML will blow HTTP caches for you.
- This makes it easy to HTTP-cache many more of your actions.
-
- If you render a different template, you can now pass the `:template`
- option to include its digest instead:
-
- fresh_when @post, template: 'widgets/show'
-
- Pass `template: false` to skip the lookup. To turn this off entirely, set:
-
- config.action_controller.etag_with_template_digest = false
-
- *Jeremy Kemper*
-
-* Remove deprecated `AbstractController::Helpers::ClassMethods::MissingHelperError`
- in favor of `AbstractController::Helpers::MissingHelperError`.
-
- *Yves Senn*
-
-* Fix `assert_template` not being able to assert that no files were rendered.
-
- *Guo Xiang Tan*
-
-* Extract source code for the entire exception stack trace for
- better debugging and diagnosis.
-
- *Ryan Dao*
-
-* Allows ActionDispatch::Request::LOCALHOST to match any IPv4 127.0.0.0/8
- loopback address.
-
- *Earl St Sauver*, *Sven Riedel*
-
-* Preserve original path in `ShowExceptions` middleware by stashing it as
- `env["action_dispatch.original_path"]`
-
- `ActionDispatch::ShowExceptions` overwrites `PATH_INFO` with the status code
- for the exception defined in `ExceptionWrapper`, so the path
- the user was visiting when an exception occurred was not previously
- available to any custom exceptions_app. The original `PATH_INFO` is now
- stashed in `env["action_dispatch.original_path"]`.
-
- *Grey Baker*
-
-* Use `String#bytesize` instead of `String#size` when checking for cookie
- overflow.
-
- *Agis Anastasopoulos*
-
-* `render nothing: true` or rendering a `nil` body no longer add a single
- space to the response body.
-
- The old behavior was added as a workaround for a bug in an early version of
- Safari, where the HTTP headers are not returned correctly if the response
- body has a 0-length. This is been fixed since and the workaround is no
- longer necessary.
-
- Use `render body: ' '` if the old behavior is desired.
-
- See #14883 for details.
-
- *Godfrey Chan*
-
-* Prepend a JS comment to JSONP callbacks. Addresses CVE-2014-4671
- ("Rosetta Flash").
-
- *Greg Campbell*
-
-* Because URI paths may contain non US-ASCII characters we need to force
- the encoding of any unescaped URIs to UTF-8 if they are US-ASCII.
- This essentially replicates the functionality of the monkey patch to
- URI.parser.unescape in active_support/core_ext/uri.rb.
-
- Fixes #16104.
-
- *Karl Entwistle*
-
-* 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`.
-
- *Aaron Patterson*
-
-* 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.
-
- *Christiaan Van den Poel*
-
-* Add MKCALENDAR HTTP method (RFC 4791).
-
- *Sergey Karpesh*
-
-* Instrument fragment cache metrics.
-
- Adds `:controller`: and `:action` keys to the instrumentation payload
- for the `*_fragment.action_controller` notifications. This allows tracking
- e.g. the fragment cache hit rates for each controller action.
-
- *Daniel Schierbeck*
-
-* Always use the provided port if the protocol is relative.
-
- Fixes #15043.
-
- *Guilherme Cavalcanti*, *Andrew White*
-
-* Moved `params[request_forgery_protection_token]` into its own method
- and improved tests.
-
- Fixes #11316.
-
- *Tom Kadwill*
-
-* Added verification of route constraints given as a Proc or an object responding
- to `:matches?`. Previously, when given an non-complying object, it would just
- silently fail to enforce the constraint. It will now raise an `ArgumentError`
- when setting up the routes.
-
- *Xavier Defrang*
-
-* Properly treat the entire IPv6 User Local Address space as private for
- purposes of remote IP detection. Also handle uppercase private IPv6
- addresses.
-
- Fixes #12638.
-
- *Caleb Spare*
-
-* Fixed an issue with migrating legacy json cookies.
-
- Previously, the `VerifyAndUpgradeLegacySignedMessage` assumes all incoming
- cookies are marshal-encoded. This is not the case when `secret_token` is
- used in conjunction with the `:json` or `:hybrid` serializer.
-
- In those case, when upgrading to use `secret_key_base`, this would cause a
- `TypeError: incompatible marshal file format` and a 500 error for the user.
-
- Fixes #14774.
-
- *Godfrey Chan*
-
-* Make URL escaping more consistent:
-
- 1. Escape '%' characters in URLs - only unescaped data should be passed to URL helpers
- 2. Add an `escape_segment` helper to `Router::Utils` that escapes '/' characters
- 3. Use `escape_segment` rather than `escape_fragment` in optimized URL generation
- 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
- 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.
-
- Fixes #14629, #14636 and #14070.
-
- *Andrew White*, *Edho Arief*
-
-* Add alias `ActionDispatch::Http::UploadedFile#to_io` to
- `ActionDispatch::Http::UploadedFile#tempfile`.
-
- *Tim Linquist*
-
-* Returns null type format when format is not know and controller is using `any`
- format block.
-
- Fixes #14462.
-
- *Rafael Mendonça França*
-
-* Improve routing error page with fuzzy matching search.
-
- *Winston*
-
-* Only make deeply nested routes shallow when parent is shallow.
-
- Fixes #14684.
-
- *Andrew White*, *James Coglan*
-
-* 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.
-
- Fixes #14422.
-
- *Vishal Lal*
-
-* The method `shallow?` returns false if the parent resource is a singleton so
- we need to check if we're not inside a nested scope before copying the :path
- and :as options to their shallow equivalents.
-
- Fixes #14388.
-
- *Andrew White*
-
-* Make logging of CSRF failures optional (but on by default) with the
- `log_warning_on_csrf_failure` configuration setting in
- `ActionController::RequestForgeryProtection`.
-
- *John Barton*
-
-* Fix URL generation in controller tests with request-dependent
- `default_url_options` methods.
-
- *Tony Wooster*
-
-Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/actionpack/CHANGELOG.md) for previous changes.
+Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/actionpack/CHANGELOG.md) for previous changes.
diff --git a/actionpack/RUNNING_UNIT_TESTS.rdoc b/actionpack/RUNNING_UNIT_TESTS.rdoc
deleted file mode 100644
index f96a9d9da5..0000000000
--- a/actionpack/RUNNING_UNIT_TESTS.rdoc
+++ /dev/null
@@ -1,17 +0,0 @@
-== Running with Rake
-
-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://docs.seattlerb.org/rake/.
-
-== Running by hand
-
-Run a single test suite:
-
- rake test TEST=path/to/test.rb
-
-Run one test in a test suite:
-
- rake test TEST=path/to/test.rb TESTOPTS="--name=test_something"
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index af075f82ad..4b60b77759 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -16,6 +16,7 @@ Rake::TestTask.new do |t|
t.warning = true
t.verbose = true
+ t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end
namespace :test do
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index c752388e28..f83823dd75 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.'
- s.required_ruby_version = '>= 1.9.3'
+ s.required_ruby_version = '>= 2.2.0'
s.license = 'MIT'
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
s.add_dependency 'activesupport', version
- s.add_dependency 'rack', '~> 1.6.0.beta'
+ s.add_dependency 'rack', '~> 1.6.0'
s.add_dependency 'rack-test', '~> 0.6.2'
- s.add_dependency 'rails-html-sanitizer', '~> 1.0'
- s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.2'
+ s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1'
+ s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5'
s.add_dependency 'actionview', version
s.add_development_dependency 'activemodel', version
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 4026dab2ce..51c661f735 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -82,7 +82,7 @@ module AbstractController
# Except for public instance methods of Base and its ancestors
internal_methods +
# Be sure to include shadowed public instance methods of this class
- public_instance_methods(false)).uniq.map { |x| x.to_s } -
+ public_instance_methods(false)).uniq.map(&:to_s) -
# And always exclude explicitly hidden actions
hidden_actions.to_a
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 95c67d482b..df7382f02d 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -150,7 +150,17 @@ module AbstractController
rescue LoadError => e
raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
end
- file_name.camelize.constantize
+
+ mod_name = file_name.camelize
+ begin
+ mod_name.constantize
+ rescue LoadError
+ # dependencies.rb gives a similar error message but its wording is
+ # not as clear because it mentions autoloading. To the user all it
+ # matters is that a helper module couldn't be loaded, autoloading
+ # is an internal mechanism that should not leak.
+ raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
+ end
when Module
arg
else
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 7f1aeafe8b..91ac7eef01 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -34,7 +34,6 @@ module ActionController
autoload :Rendering
autoload :RequestForgeryProtection
autoload :Rescue
- autoload :Responder
autoload :Streaming
autoload :StrongParameters
autoload :Testing
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 7bbf938987..5cb11bc479 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -44,7 +44,7 @@ module ActionController
# The full request object is available via the request accessor and is primarily used to query for HTTP headers:
#
# def server_ip
- # location = request.env["SERVER_ADDR"]
+ # location = request.env["REMOTE_ADDR"]
# render plain: "This server hosted at #{location}"
# end
#
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 89fa75f025..87609d8aa7 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -1,4 +1,3 @@
-
module ActionController
class LogSubscriber < ActiveSupport::LogSubscriber
INTERNAL_PARAMS = %w(controller action format _method only_path)
@@ -54,15 +53,6 @@ module ActionController
end
end
- def deep_munge(event)
- debug do
- "Value for params[:#{event.payload[:keys].join('][:')}] was set "\
- "to nil, because it was one of [], [null] or [null, null, ...]. "\
- "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation "\
- "for more information."\
- end
- end
-
%w(write_fragment read_fragment exist_fragment?
expire_fragment expire_page write_page).each do |method|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index bfbc15a901..6dd213b2f7 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -165,7 +165,7 @@ module ActionController
headers["Location"] = url
end
- # basic url_for that can be overridden for more robust functionality
+ # Basic url_for that can be overridden for more robust functionality
def url_for(string)
string
end
@@ -182,7 +182,7 @@ module ActionController
body = [body] unless body.nil? || body.respond_to?(:each)
super
end
-
+
# Tests if render or redirect has already happened.
def performed?
response_body || (response && response.committed?)
@@ -237,7 +237,7 @@ module ActionController
end
end
- def _status_code
+ def _status_code #:nodoc:
@_status
end
end
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index a93727df90..b210ee3423 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -13,9 +13,9 @@ module ActionController
end
module ClassMethods
- # Allows you to consider additional controller-wide information when generating an etag.
+ # Allows you to consider additional controller-wide information when generating an ETag.
# For example, if you serve pages tailored depending on who's logged in at the moment, you
- # may want to add the current user id to be part of the etag to prevent authorized displaying
+ # may want to add the current user id to be part of the ETag to prevent authorized displaying
# of cached pages.
#
# class InvoicesController < ApplicationController
@@ -32,7 +32,7 @@ module ActionController
end
end
- # Sets the etag, +last_modified+, or both on the response and renders a
+ # Sets the +etag+, +last_modified+, or both on the response and renders a
# <tt>304 Not Modified</tt> response if the request is already fresh.
#
# === Parameters:
@@ -54,11 +54,11 @@ module ActionController
# fresh_when(etag: @article, last_modified: @article.created_at, public: true)
# end
#
- # This will render the show template if the request isn't sending a matching etag or
+ # This will render the show template if the request isn't sending a matching ETag or
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
#
# You can also just pass a record where +last_modified+ will be set by calling
- # +updated_at+ and the etag by passing the object itself.
+ # +updated_at+ and the +etag+ by passing the object itself.
#
# def show
# @article = Article.find(params[:id])
@@ -124,7 +124,7 @@ module ActionController
# end
#
# You can also just pass a record where +last_modified+ will be set by calling
- # updated_at and the etag by passing the object itself.
+ # +updated_at+ and the +etag+ by passing the object itself.
#
# def show
# @article = Article.find(params[:id])
diff --git a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
index 3ca0c6837a..f9303efe6c 100644
--- a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
+++ b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
@@ -7,8 +7,8 @@ module ActionController
#
# config.action_controller.etag_with_template_digest = false
#
- # Override the template to digest by passing `:template` to `fresh_when`
- # and `stale?` calls. For example:
+ # Override the template to digest by passing +:template+ to +fresh_when+
+ # and +stale?+ calls. For example:
#
# # We're going to render widgets/show, not posts/show
# fresh_when @post, template: 'widgets/show'
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb
index 3844dbf2a6..18e003741d 100644
--- a/actionpack/lib/action_controller/metal/exceptions.rb
+++ b/actionpack/lib/action_controller/metal/exceptions.rb
@@ -25,7 +25,7 @@ module ActionController
end
end
- class ActionController::UrlGenerationError < RoutingError #:nodoc:
+ class ActionController::UrlGenerationError < ActionControllerError #:nodoc:
end
class MethodNotAllowed < ActionControllerError #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 3d2badf9c2..57e60222cd 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -29,14 +29,14 @@ module ActionController
self.status = status
self.location = url_for(location) if location
+ self.response_body = ""
+
if include_content?(self._status_code)
self.content_type = content_type || (Mime[formats.first] if formats)
self.response.charset = false if self.response
- self.response_body = " "
else
headers.delete('Content-Type')
headers.delete('Content-Length')
- self.response_body = ""
end
end
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 25c123edf7..a219d35b25 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -53,10 +53,8 @@ module ActionController
# In your integration tests, you can do something like this:
#
# def test_access_granted_from_xml
- # get(
- # "/notes/1.xml", nil,
- # 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
- # )
+ # @request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
+ # get "/notes/1.xml"
#
# assert_equal 200, status
# end
@@ -397,6 +395,7 @@ module ActionController
#
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
module Token
+ TOKEN_KEY = 'token='
TOKEN_REGEX = /^Token /
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
extend self
@@ -462,16 +461,22 @@ module ActionController
raw_params.map { |param| param.split %r/=(.+)?/ }
end
- # This removes the `"` characters wrapping the value.
+ # This removes the <tt>"</tt> characters wrapping the value.
def rewrite_param_values(array_params)
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`.
+ # pairs by the standardized <tt>:</tt>, <tt>;</tt>, or <tt>\t</tt>
+ # delimiters defined in +AUTHN_PAIR_DELIMITERS+.
def raw_params(auth)
- auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
+ _raw_params = auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
+
+ if !(_raw_params.first =~ %r{\A#{TOKEN_KEY}})
+ _raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}"
+ end
+
+ _raw_params
end
# Encodes the given token and options into an Authorization header value.
@@ -481,7 +486,7 @@ module ActionController
#
# Returns String.
def encode_credentials(token, options = {})
- values = ["token=#{token.to_s.inspect}"] + options.map do |key, value|
+ values = ["#{TOKEN_KEY}#{token.to_s.inspect}"] + options.map do |key, value|
"#{key}=#{value.to_s.inspect}"
end
"Token #{values * ", "}"
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index b0e164bc57..bef7545e71 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -21,7 +21,7 @@ module ActionController
:action => self.action_name,
:params => request.filtered_parameters,
:format => request.format.try(:ref),
- :method => request.method,
+ :method => request.request_method,
:path => (request.fullpath rescue "unknown")
}
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index c9ef3a3dad..7590fb6843 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -102,7 +102,7 @@ module ActionController
end
end
- message = json.gsub("\n", "\ndata: ")
+ message = json.gsub(/\n/, "\ndata: ")
@stream.write "data: #{message}\n\n"
end
end
@@ -189,12 +189,6 @@ module ActionController
!@aborted
end
- def await_close
- synchronize do
- @cv.wait_until { @closed }
- end
- end
-
def on_error(&block)
@error_callback = block
end
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index dc572f13d2..ac1f209232 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -135,18 +135,6 @@ module ActionController #:nodoc:
#
# render json: @people
#
- # Since this is a common pattern, you can use the class method respond_to
- # with the respond_with method to have the same results:
- #
- # class PeopleController < ApplicationController
- # respond_to :html, :xml, :json
- #
- # def index
- # @people = Person.all
- # respond_with(@people)
- # end
- # end
- #
# Formats can have different variants.
#
# The request variant is a specialization of the request format, like <tt>:tablet</tt>,
@@ -214,13 +202,13 @@ module ActionController #:nodoc:
# format.html.phone # this gets rendered
# end
#
- # Be sure to check the documentation of +respond_with+ and
- # <tt>ActionController::MimeResponds.respond_to</tt> for more examples.
- def respond_to(*mimes, &block)
+ # Be sure to check the documentation of <tt>ActionController::MimeResponds.respond_to</tt>
+ # for more examples.
+ def respond_to(*mimes)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
collector = Collector.new(mimes, request.variant)
- block.call(collector) if block_given?
+ yield collector if block_given?
if format = collector.negotiate_format(request)
_process_format(format)
@@ -234,8 +222,8 @@ module ActionController #:nodoc:
# A container for responses available from the current controller for
# requests for different mime-types sent to a particular action.
#
- # The public controller methods +respond_with+ and +respond_to+ may be called
- # with a block that is used to define responses to different mime-types, e.g.
+ # The public controller methods +respond_to+ may be called with a block
+ # that is used to define responses to different mime-types, e.g.
# for +respond_to+ :
#
# respond_to do |format|
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 2ca8955741..b44493ff7c 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -86,7 +86,7 @@ module ActionController
new name, format, include, exclude, nil, nil
end
- def initialize(name, format, include, exclude, klass, model) # nodoc
+ def initialize(name, format, include, exclude, klass, model) # :nodoc:
super
@include_set = include
@name_set = name
@@ -244,7 +244,7 @@ module ActionController
request.parameters.merge! wrapped_hash
request.request_parameters.merge! wrapped_hash
- # This will make the wrapped hash displayed in the log file
+ # This will display the wrapped hash in the log file
request.filtered_parameters.merge! wrapped_filtered_hash
end
super
@@ -252,7 +252,7 @@ module ActionController
private
- # Returns the wrapper key which will use to stored wrapped parameters.
+ # Returns the wrapper key which will be used to stored wrapped parameters.
def _wrapper_key
_wrapper_options.name
end
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 6921834044..545d4a7e6e 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -6,7 +6,7 @@ module ActionController
extend ActiveSupport::Concern
delegate :headers, :status=, :location=, :content_type=,
- :status, :location, :content_type, :_status_code, :to => "@_response"
+ :status, :location, :content_type, :response_code, :to => "@_response"
def dispatch(action, request)
set_response!(request)
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index bc94536c8c..45d3962494 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -86,8 +86,7 @@ module ActionController
# end
# end
# To use renderers and their mime types in more concise ways, see
- # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
- # <tt>ActionController::MimeResponds#respond_with</tt>
+ # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt>
def self.add(key, &block)
define_method(_render_with_renderer_method_name(key), &block)
RENDERERS << key.to_sym
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index a4f376816f..d1fab27e17 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -1,5 +1,6 @@
require 'rack/session/abstract/id'
require 'action_controller/metal/exceptions'
+require 'active_support/security_utils'
module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
@@ -208,6 +209,7 @@ module ActionController #:nodoc:
forgery_protection_strategy.new(self).handle_unverified_request
end
+ #:nodoc:
CROSS_ORIGIN_JAVASCRIPT_WARNING = "Security warning: an embedded " \
"<script> tag on another site requested protected JavaScript. " \
"If you know what you're doing, go ahead and disable forgery " \
@@ -305,8 +307,7 @@ module ActionController #:nodoc:
end
def compare_with_real_token(token, session)
- # Borrow a constant-time comparison from Rack
- Rack::Utils.secure_compare(token, real_csrf_token(session))
+ ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
end
def real_csrf_token(session)
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 7038f0997f..01bbd749c1 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/core_ext/string/filters'
require 'active_support/deprecation'
require 'active_support/rescuable'
require 'action_dispatch/http/upload'
@@ -91,7 +92,11 @@ module ActionController
# params.permit(:c)
# # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
#
- # <tt>ActionController::Parameters</tt> is inherited from
+ # Please note that these options *are not thread-safe*. In a multi-threaded
+ # environment they should only be set once at boot-time and never mutated at
+ # runtime.
+ #
+ # <tt>ActionController::Parameters</tt> inherits from
# <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means
# that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
#
@@ -114,10 +119,12 @@ module ActionController
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
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
+ Use `ActionController::Parameters.always_permitted_parameters` instead.
+ MSG
+
+ always_permitted_parameters
end
# Returns a new instance of <tt>ActionController::Parameters</tt>.
@@ -160,6 +167,12 @@ module ActionController
end
end
+ # Returns an unsafe, unfiltered +Hash+ representation of this parameter.
+ def to_unsafe_h
+ to_hash
+ end
+ alias_method :to_unsafe_hash, :to_unsafe_h
+
# Convert all hashes in values into parameters, then yield each pair like
# the same way as <tt>Hash#each_pair</tt>
def each_pair(&block)
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index dd8da4b5dc..d01927b7cb 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -24,7 +24,7 @@ module ActionController
module ClassMethods
def before_filters
- _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
+ _process_action_callbacks.find_all{|x| x.kind == :before}.map(&:name)
end
end
end
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 0f2fa5fb08..572d1770f7 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -30,9 +30,9 @@ module ActionController
:_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"]) ||
- (original_script_name = env['ORIGINAL_SCRIPT_NAME'.freeze])
+ if (same_origin = _routes.equal?(request.routes)) ||
+ (script_name = request.engine_script_name(_routes)) ||
+ (original_script_name = request.original_script_name)
options = @_url_options.dup
if original_script_name
diff --git a/actionpack/lib/action_controller/model_naming.rb b/actionpack/lib/action_controller/model_naming.rb
deleted file mode 100644
index 2b33f67263..0000000000
--- a/actionpack/lib/action_controller/model_naming.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module ActionController
- module ModelNaming
- # Converts the given object to an ActiveModel compliant one.
- def convert_to_model(object)
- object.respond_to?(:to_model) ? object.to_model : object
- end
-
- def model_name_from_record_or_class(record_or_class)
- convert_to_model(record_or_class).model_name
- end
- end
-end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 8c10c3e7b0..b9172f8fa3 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -2,6 +2,7 @@ require 'rack/session/abstract/id'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/module/anonymous'
require 'active_support/core_ext/hash/keys'
+require 'active_support/deprecation'
require 'rails-dom-testing'
@@ -144,6 +145,8 @@ module ActionController
assert(@_layouts.keys.any? {|l| l =~ expected_layout }, msg)
when nil, false
assert(@_layouts.empty?, msg)
+ else
+ raise ArgumentError, "assert_template only accepts a String, Symbol, Regexp, nil or false for :layout"
end
end
@@ -710,7 +713,28 @@ module ActionController
:relative_url_root => nil,
:_recall => @request.path_parameters)
- url, query_string = @routes.path_for(options).split("?", 2)
+ if route_name = options.delete(:use_route)
+ ActiveSupport::Deprecation.warn <<-MSG.squish
+ Passing the `use_route` option in functional tests are deprecated.
+ Support for this option in the `process` method (and the related
+ `get`, `head`, `post`, `patch`, `put` and `delete` helpers) will
+ be removed in the next version without replacement.
+
+ Functional tests are essentially unit tests for controllers and
+ they should not require knowledge to how the application's routes
+ are configured. Instead, you should explicitly pass the appropiate
+ params to the `process` method.
+
+ Previously the engines guide also contained an incorrect example
+ that recommended using this option to test an engine's controllers
+ within the dummy application. That recommendation was incorrect
+ and has since been corrected. Instead, you should override the
+ `@routes` variable in the test case with `Foo::Engine.routes`. See
+ the updated engines guide for details.
+ MSG
+ end
+
+ url, query_string = @routes.path_for(options, route_name).split("?", 2)
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
@request.env["PATH_INFO"] = url
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index 9c8f65deac..53a98c5d0a 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -72,11 +72,12 @@ module ActionDispatch
end
end
end
+
# Sets the \variant for template.
def variant=(variant)
if variant.is_a?(Symbol)
@variant = [variant]
- elsif variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
+ elsif variant.nil? || variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
@variant = variant
else
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols, not a #{variant.class}. " \
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 9450be838c..047a17937a 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -6,7 +6,7 @@ require 'active_support/core_ext/string/starts_ends_with'
module Mime
class Mimes < Array
def symbols
- @symbols ||= map { |m| m.to_sym }
+ @symbols ||= map(&:to_sym)
end
%w(<< concat shift unshift push pop []= clear compact! collect!
@@ -45,8 +45,8 @@ module Mime
#
# respond_to do |format|
# format.html
- # format.ics { render text: post.to_ics, mime_type: Mime::Type["text/calendar"] }
- # format.xml { render xml: @people }
+ # format.ics { render text: @post.to_ics, mime_type: Mime::Type["text/calendar"] }
+ # format.xml { render xml: @post }
# end
# end
# end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index b655a54865..df4b073a17 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -56,7 +56,7 @@ module ActionDispatch
elsif value.is_a?(Array)
value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
elsif blocks.any?
- key = key.dup
+ key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 20ae48d458..a5cd26a3c1 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -27,7 +27,7 @@ module ActionDispatch
def symbolized_path_parameters
ActiveSupport::Deprecation.warn(
- "`symbolized_path_parameters` is deprecated. Please use `path_parameters`"
+ '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
)
path_parameters
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index c441f7f95b..d211ea2b77 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -105,6 +105,18 @@ module ActionDispatch
@request_method ||= check_method(env["REQUEST_METHOD"])
end
+ def routes # :nodoc:
+ env["action_dispatch.routes".freeze]
+ end
+
+ def original_script_name # :nodoc:
+ env['ORIGINAL_SCRIPT_NAME'.freeze]
+ end
+
+ def engine_script_name(_routes) # :nodoc:
+ env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]
+ end
+
def request_method=(request_method) #:nodoc:
if check_method(request_method)
@request_method = env["REQUEST_METHOD"] = request_method
@@ -298,7 +310,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 || {}))
- rescue TypeError, Rack::Utils::InvalidParameterError => e
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
raise ActionController::BadRequest.new(:query, e)
end
alias :query_parameters :GET
@@ -306,7 +318,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 || {}))
- rescue TypeError, Rack::Utils::InvalidParameterError => e
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
raise ActionController::BadRequest.new(:request, e)
end
alias :request_parameters :POST
@@ -328,7 +340,7 @@ module ActionDispatch
# Extracted into ActionDispatch::Request::Utils.deep_munge, but kept here for backwards compatibility.
def deep_munge(hash)
ActiveSupport::Deprecation.warn(
- "This method has been extracted into ActionDispatch::Request::Utils.deep_munge. Please start using that instead."
+ 'This method has been extracted into `ActionDispatch::Request::Utils.deep_munge`. Please start using that instead.'
)
Utils.deep_munge(hash)
@@ -341,7 +353,7 @@ module ActionDispatch
private
def check_method(name)
- HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
name
end
end
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 2fab6be1a5..33de2f8b5f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,4 +1,6 @@
require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/string/filters'
+require 'active_support/deprecation'
require 'action_dispatch/http/filter_redirect'
require 'monitor'
@@ -274,12 +276,27 @@ module ActionDispatch # :nodoc:
end
# Turns the Response into a Rack-compatible array of the status, headers,
- # and body.
+ # and body. Allows explict splatting:
+ #
+ # status, headers, body = *response
def to_a
rack_response @status, @header.to_hash
end
alias prepare! to_a
- alias to_ary to_a
+
+ # Be super clear that a response object is not an Array. Defining this
+ # would make implicit splatting work, but it also makes adding responses
+ # as arrays work, and "flattening" responses, cascading to the rack body!
+ # Not sensible behavior.
+ def to_ary
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionDispatch::Response#to_ary` no longer performs implicit conversion
+ to an array. Please use `response.to_a` instead, or a splat like `status,
+ headers, body = *response`.
+ MSG
+
+ to_a
+ end
# Returns the response cookies, converted to a Hash of (name => value) pairs
#
@@ -298,9 +315,6 @@ module ActionDispatch # :nodoc:
cookies
end
- def _status_code
- @status
- end
private
def before_committed
@@ -369,6 +383,10 @@ module ActionDispatch # :nodoc:
def to_path
@response.stream.to_path
end
+
+ def to_ary
+ nil
+ end
end
def rack_response(status, header)
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 6b8dcaf497..001b14ec97 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -12,10 +12,22 @@ module ActionDispatch
self.tld_length = 1
class << self
+ # Returns the domain part of a host given the domain level.
+ #
+ # # Top-level domain example
+ # extract_domain('www.example.com', 1) # => "example.com"
+ # # Second-level domain example
+ # extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
def extract_domain(host, tld_length)
extract_domain_from(host, tld_length) if named_host?(host)
end
+ # Returns the subdomains of a host as an Array given the domain level.
+ #
+ # # Top-level domain example
+ # extract_subdomains('www.example.com', 1) # => ["www"]
+ # # Second-level domain example
+ # extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
def extract_subdomains(host, tld_length)
if named_host?(host)
extract_subdomains_from(host, tld_length)
@@ -24,6 +36,12 @@ module ActionDispatch
end
end
+ # Returns the subdomains of a host as a String given the domain level.
+ #
+ # # Top-level domain example
+ # extract_subdomain('www.example.com', 1) # => "www"
+ # # Second-level domain example
+ # extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
def extract_subdomain(host, tld_length)
extract_subdomains(host, tld_length).join('.')
end
@@ -68,7 +86,9 @@ module ActionDispatch
end
def add_anchor(path, anchor)
- path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param.to_s)}"
+ if anchor
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
+ end
end
def extract_domain_from(host, tld_length)
@@ -171,16 +191,43 @@ module ActionDispatch
end
# Returns the complete URL used for this request.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req.url # => "http://example.com"
def url
protocol + host_with_port + fullpath
end
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req.protocol # => "http://"
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
+ # req.protocol # => "https://"
def protocol
@protocol ||= ssl? ? 'https://' : 'http://'
end
# Returns the \host for this request, such as "example.com".
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req.raw_host_with_port # => "example.com"
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.raw_host_with_port # => "example.com:8080"
def raw_host_with_port
if forwarded = env["HTTP_X_FORWARDED_HOST"]
forwarded.split(/,\s?/).last
@@ -190,17 +237,44 @@ module ActionDispatch
end
# Returns the host for this request, such as example.com.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.host # => "example.com"
def host
raw_host_with_port.sub(/:\d+$/, '')
end
# Returns a \host:\port string for this request, such as "example.com" or
# "example.com:8080".
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req.host_with_port # => "example.com"
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.host_with_port # => "example.com:8080"
def host_with_port
"#{host}#{port_string}"
end
# Returns the port number of this request as an integer.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req.port # => 80
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.port # => 8080
def port
@port ||= begin
if raw_host_with_port =~ /:(\d+)$/
@@ -212,6 +286,13 @@ module ActionDispatch
end
# Returns the standard \port number for this request's protocol.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.standard_port # => 80
def standard_port
case protocol
when 'https://' then 443
@@ -220,18 +301,48 @@ module ActionDispatch
end
# Returns whether this request is using the standard port
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req.standard_port? # => true
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.standard_port? # => false
def standard_port?
port == standard_port
end
# Returns a number \port suffix like 8080 if the \port number of this request
# is not the default HTTP \port 80 or HTTPS \port 443.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req.optional_port # => nil
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.optional_port # => 8080
def optional_port
standard_port? ? nil : port
end
# Returns a string \port suffix, including colon, like ":8080" if the \port
# number of this request is not the default HTTP \port 80 or HTTPS \port 443.
+ #
+ # class Request < Rack::Request
+ # include ActionDispatch::Http::URL
+ # end
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req.port_string # => ""
+ #
+ # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req.port_string # => ":8080"
def port_string
standard_port? ? '' : ":#{port}"
end
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 59b353b1b7..177f586c0e 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -1,4 +1,5 @@
require 'action_controller/metal/exceptions'
+require 'active_support/deprecation'
module ActionDispatch
module Journey
@@ -40,7 +41,7 @@ module ActionDispatch
end
message = "No route matches #{Hash[constraints.sort].inspect}"
- message << " missing required keys: #{missing_keys.sort.inspect}" if name
+ message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
raise ActionController::UrlGenerationError, message
end
@@ -80,6 +81,9 @@ module ActionDispatch
if named_routes.key?(name)
yield named_routes[name]
else
+ # Make sure we don't show the deprecation warning more than once
+ warned = false
+
routes = non_recursive(cache, options)
hash = routes.group_by { |_, r| r.score(options) }
@@ -88,6 +92,17 @@ module ActionDispatch
break if score < 0
hash[score].sort_by { |i, _| i }.each do |_, route|
+ if name && !warned
+ ActiveSupport::Deprecation.warn <<-MSG.squish
+ You are trying to generate the URL for a named route called
+ #{name.inspect} but no such route was found. In the future,
+ this will result in an `ActionController::UrlGenerationError`
+ exception.
+ MSG
+
+ warned = true
+ end
+
yield route
end
end
diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
index 990d2127ee..1b914f0637 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
@@ -88,13 +88,13 @@ module ActionDispatch
erb = File.read File.join(viz_dir, 'index.html.erb')
states = "function tt() { return #{to_json}; }"
- fun_routes = paths.shuffle.first(3).map do |ast|
+ fun_routes = paths.sample(3).map do |ast|
ast.map { |n|
case n
when Nodes::Symbol
case n.left
when ':id' then rand(100).to_s
- when ':format' then %w{ xml json }.shuffle.first
+ when ':format' then %w{ xml json }.sample
else
'omg'
end
diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
index 66e414213a..0ccab21801 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
@@ -45,51 +45,6 @@ module ActionDispatch
(@table.keys + @table.values.flat_map(&:keys)).uniq
end
- # Returns a generalized transition graph with reduced states. The states
- # are reduced like a DFA, but the table must be simulated like an NFA.
- #
- # Edges of the GTG are regular expressions.
- def generalized_table
- gt = GTG::TransitionTable.new
- marked = {}
- state_id = Hash.new { |h,k| h[k] = h.length }
- alphabet = self.alphabet
-
- stack = [eclosure(0)]
-
- until stack.empty?
- state = stack.pop
- next if marked[state] || state.empty?
-
- marked[state] = true
-
- alphabet.each do |alpha|
- next_state = eclosure(following_states(state, alpha))
- next if next_state.empty?
-
- gt[state_id[state], state_id[next_state]] = alpha
- stack << next_state
- end
- end
-
- final_groups = state_id.keys.find_all { |s|
- s.sort.last == accepting
- }
-
- final_groups.each do |states|
- id = state_id[states]
-
- gt.add_accepting(id)
- save = states.find { |s|
- @memos.key?(s) && eclosure(s).sort.last == accepting
- }
-
- gt.add_memo(id, memo(save))
- end
-
- gt
- end
-
# Returns set of NFA states to which there is a transition on ast symbol
# +a+ from some state +s+ in +t+.
def following_states(t, a)
@@ -107,7 +62,7 @@ module ActionDispatch
end
def alphabet
- inverted.values.flat_map(&:keys).compact.uniq.sort_by { |x| x.to_s }
+ inverted.values.flat_map(&:keys).compact.uniq.sort_by(&:to_s)
end
# Returns a set of NFA states reachable from some NFA state +s+ in set
diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb
index 3af940a02f..64b48ca45f 100644
--- a/actionpack/lib/action_dispatch/journey/path/pattern.rb
+++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb
@@ -42,7 +42,7 @@ module ActionDispatch
end
def names
- @names ||= spec.grep(Nodes::Symbol).map { |n| n.name }
+ @names ||= spec.grep(Nodes::Symbol).map(&:name)
end
def required_names
@@ -52,7 +52,7 @@ module ActionDispatch
def optional_names
@optional_names ||= spec.grep(Nodes::Group).flat_map { |group|
group.grep(Nodes::Symbol)
- }.map { |n| n.name }.uniq
+ }.map(&:name).uniq
end
class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
@@ -122,6 +122,11 @@ module ActionDispatch
re = @matchers[node.left.to_sym] || '.+'
"(#{re})"
end
+
+ def visit_OR(node)
+ children = node.children.map { |n| visit n }
+ "(?:#{children.join(?|)})"
+ end
end
class UnanchoredRegexp < AnchoredRegexp # :nodoc:
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 9f0a3af902..4d5c18984a 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -60,7 +60,7 @@ module ActionDispatch
end
def parts
- @parts ||= segments.map { |n| n.to_sym }
+ @parts ||= segments.map(&:to_sym)
end
alias :segment_keys :parts
@@ -68,12 +68,8 @@ module ActionDispatch
@path_formatter.evaluate path_options
end
- def optional_parts
- path.optional_names.map { |n| n.to_sym }
- end
-
def required_parts
- @required_parts ||= path.required_names.map { |n| n.to_sym }
+ @required_parts ||= path.required_names.map(&:to_sym)
end
def required_default?(key)
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 9131b65380..2b036796ab 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -68,8 +68,8 @@ module ActionDispatch
def visualizer
tt = GTG::Builder.new(ast).transition_table
- groups = partitioned_routes.first.map(&:ast).group_by { |a| a.to_s }
- asts = groups.values.map { |v| v.first }
+ groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
+ asts = groups.values.map(&:first)
tt.visualizer(asts)
end
diff --git a/actionpack/lib/action_dispatch/journey/scanner.rb b/actionpack/lib/action_dispatch/journey/scanner.rb
index 633be11a2d..19e0bc03d6 100644
--- a/actionpack/lib/action_dispatch/journey/scanner.rb
+++ b/actionpack/lib/action_dispatch/journey/scanner.rb
@@ -39,18 +39,18 @@ module ActionDispatch
[:SLASH, text]
when text = @ss.scan(/\*\w+/)
[:STAR, text]
- when text = @ss.scan(/\(/)
+ when text = @ss.scan(/(?<!\\)\(/)
[:LPAREN, text]
- when text = @ss.scan(/\)/)
+ when text = @ss.scan(/(?<!\\)\)/)
[:RPAREN, text]
when text = @ss.scan(/\|/)
[:OR, text]
when text = @ss.scan(/\./)
[:DOT, text]
- when text = @ss.scan(/:\w+/)
+ when text = @ss.scan(/(?<!\\):\w+/)
[:SYMBOL, text]
- when text = @ss.scan(/[\w%\-~]+/)
- [:LITERAL, text]
+ when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/)
+ [:LITERAL, text.tr('\\', '')]
# any char
when text = @ss.scan(/./)
[:LITERAL, text]
diff --git a/actionpack/lib/action_dispatch/journey/visualizer/fsm.css b/actionpack/lib/action_dispatch/journey/visualizer/fsm.css
index 50caebaa18..403e16a7bb 100644
--- a/actionpack/lib/action_dispatch/journey/visualizer/fsm.css
+++ b/actionpack/lib/action_dispatch/journey/visualizer/fsm.css
@@ -16,10 +16,6 @@ h2 {
font-size: 0.5em;
}
-div#chart-2 {
- height: 350px;
-}
-
.clearfix {display: inline-block; }
.input { overflow: show;}
.instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em}
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index baf9d5779e..f80df78582 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -1,6 +1,6 @@
module ActionDispatch
- # Provide callbacks to be executed before and after the request dispatch.
+ # Provides callbacks to be executed before and after dispatching the request.
class Callbacks
include ActiveSupport::Callbacks
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 83ac62a83d..8d3ce24612 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -71,11 +71,13 @@ module ActionDispatch
# restrict to the domain level. If you use a schema like www.example.com
# and want to share session with user.example.com set <tt>:domain</tt>
# to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
- # <tt>:all</tt> again when deleting cookies.
+ # <tt>:all</tt> or <tt>Array</tt> again when deleting cookies.
#
# domain: nil # Does not sets cookie domain. (default)
# domain: :all # Allow the cookie for the top most level
# # domain and subdomains.
+ # domain: %w(.example.com .example.org) # Allow the cookie
+ # # for concrete domain names.
#
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
@@ -120,7 +122,7 @@ module ActionDispatch
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
# cookie was tampered with by the user (or a 3rd party), nil will be returned.
#
- # If +secrets.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
+ # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
# legacy cookies signed with the old key generator will be transparently upgraded.
#
# This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
@@ -143,7 +145,7 @@ module ActionDispatch
# Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
# If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
#
- # If +secrets.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
+ # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
# legacy cookies signed with the old key generator will be transparently upgraded.
#
# This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
@@ -281,7 +283,7 @@ module ActionDispatch
def handle_options(options) #:nodoc:
options[:path] ||= "/"
- if options[:domain] == :all
+ if options[:domain] == :all || options[:domain] == 'all'
# if there is a provided tld length then we use it otherwise default domain regexp
domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
@@ -408,7 +410,7 @@ module ActionDispatch
@options[:serializer] == :hybrid && value.start_with?(MARSHAL_SIGNATURE)
end
- def serialize(name, value)
+ def serialize(value)
serializer.dump(value)
end
@@ -461,9 +463,9 @@ module ActionDispatch
def []=(name, options)
if options.is_a?(Hash)
options.symbolize_keys!
- options[:value] = @verifier.generate(serialize(name, options[:value]))
+ options[:value] = @verifier.generate(serialize(options[:value]))
else
- options = { :value => @verifier.generate(serialize(name, options)) }
+ options = { :value => @verifier.generate(serialize(options)) }
end
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
@@ -479,7 +481,7 @@ module ActionDispatch
end
# UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
- # config.secret_token and secrets.secret_key_base are both set. It reads
+ # secrets.secret_token and secrets.secret_key_base are both set. It reads
# legacy cookies signed with the old dummy key generator and re-saves
# them using the new key generator to provide a smooth upgrade path.
class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
@@ -522,7 +524,7 @@ module ActionDispatch
options = { :value => options }
end
- options[:value] = @encryptor.encrypt_and_sign(serialize(name, options[:value]))
+ options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]))
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
@parent_jar[name] = options
@@ -537,7 +539,7 @@ module ActionDispatch
end
# UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
- # instead of EncryptedCookieJar if config.secret_token and secrets.secret_key_base
+ # instead of EncryptedCookieJar if secrets.secret_token and secrets.secret_key_base
# are both set. It reads legacy cookies signed with the old dummy key generator and
# encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 274f6f2f22..9082aac271 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -1,6 +1,10 @@
require 'action_dispatch/http/request'
require 'action_dispatch/middleware/exception_wrapper'
require 'action_dispatch/routing/inspector'
+require 'action_view'
+require 'action_view/base'
+
+require 'pp'
module ActionDispatch
# This middleware is responsible for logging exceptions and
@@ -8,6 +12,32 @@ module ActionDispatch
class DebugExceptions
RESCUES_TEMPLATE_PATH = File.expand_path('../templates', __FILE__)
+ class DebugView < ActionView::Base
+ def debug_params(params)
+ clean_params = params.clone
+ clean_params.delete("action")
+ clean_params.delete("controller")
+
+ if clean_params.empty?
+ 'None'
+ else
+ PP.pp(clean_params, "", 200)
+ end
+ end
+
+ def debug_headers(headers)
+ if headers.present?
+ headers.inspect.gsub(',', ",\n")
+ else
+ 'None'
+ end
+ end
+
+ def debug_hash(object)
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
+ end
+ end
+
def initialize(app, routes_app = nil)
@app = app
@routes_app = routes_app
@@ -35,12 +65,25 @@ module ActionDispatch
if env['action_dispatch.show_detailed_exceptions']
request = Request.new(env)
- template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
+ traces = wrapper.traces
+
+ trace_to_show = 'Application Trace'
+ if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
+ trace_to_show = 'Full Trace'
+ end
+
+ if source_to_show = traces[trace_to_show].first
+ source_to_show_id = source_to_show[:id]
+ end
+
+ template = DebugView.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
- traces: traces_from_wrapper(wrapper),
+ traces: traces,
+ show_source_idx: source_to_show_id,
+ trace_to_show: trace_to_show,
routes_inspector: routes_inspector(exception),
- source_extract: wrapper.source_extract,
+ source_extracts: wrapper.source_extracts,
line_number: wrapper.line_number,
file: wrapper.file
)
@@ -93,36 +136,5 @@ module ActionDispatch
ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
end
end
-
- # Augment the exception traces by providing ids for all unique stack frame
- def traces_from_wrapper(wrapper)
- application_trace = wrapper.application_trace
- framework_trace = wrapper.framework_trace
- full_trace = wrapper.full_trace
-
- if application_trace && framework_trace
- id_counter = 0
-
- application_trace = application_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
- end
-
- framework_trace = framework_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
- end
-
- full_trace = application_trace + framework_trace
- end
-
- {
- "Application Trace" => application_trace,
- "Framework Trace" => framework_trace,
- "Full Trace" => full_trace
- }
- end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index b98b553c38..a4862e33aa 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -6,16 +6,17 @@ module ActionDispatch
cattr_accessor :rescue_responses
@@rescue_responses = Hash.new(:internal_server_error)
@@rescue_responses.merge!(
- 'ActionController::RoutingError' => :not_found,
- 'AbstractController::ActionNotFound' => :not_found,
- 'ActionController::MethodNotAllowed' => :method_not_allowed,
- 'ActionController::UnknownHttpMethod' => :method_not_allowed,
- 'ActionController::NotImplemented' => :not_implemented,
- 'ActionController::UnknownFormat' => :not_acceptable,
- 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
- 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
- 'ActionController::BadRequest' => :bad_request,
- 'ActionController::ParameterMissing' => :bad_request
+ 'ActionController::RoutingError' => :not_found,
+ 'AbstractController::ActionNotFound' => :not_found,
+ 'ActionController::MethodNotAllowed' => :method_not_allowed,
+ 'ActionController::UnknownHttpMethod' => :method_not_allowed,
+ 'ActionController::NotImplemented' => :not_implemented,
+ 'ActionController::UnknownFormat' => :not_acceptable,
+ 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
+ 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity,
+ 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
+ 'ActionController::BadRequest' => :bad_request,
+ 'ActionController::ParameterMissing' => :bad_request
)
cattr_accessor :rescue_templates
@@ -56,24 +57,52 @@ module ActionDispatch
clean_backtrace(:all)
end
+ def traces
+ appplication_trace_with_ids = []
+ framework_trace_with_ids = []
+ full_trace_with_ids = []
+
+ full_trace.each_with_index do |trace, idx|
+ trace_with_id = { id: idx, trace: trace }
+
+ if application_trace.include?(trace)
+ appplication_trace_with_ids << trace_with_id
+ else
+ framework_trace_with_ids << trace_with_id
+ end
+
+ full_trace_with_ids << trace_with_id
+ end
+
+ {
+ "Application Trace" => appplication_trace_with_ids,
+ "Framework Trace" => framework_trace_with_ids,
+ "Full Trace" => full_trace_with_ids
+ }
+ end
+
def self.status_code_for_exception(class_name)
Rack::Utils.status_code(@@rescue_responses[class_name])
end
- def source_extract
- exception.backtrace.map do |trace|
+ def source_extracts
+ backtrace.map do |trace|
file, line = trace.split(":")
line_number = line.to_i
+
{
code: source_fragment(file, line_number),
- file: file,
line_number: line_number
}
- end if exception.backtrace
+ end
end
private
+ def backtrace
+ Array(@exception.backtrace)
+ end
+
def original_exception(exception)
if registered_original_exception?(exception)
exception.original_exception
@@ -88,9 +117,9 @@ module ActionDispatch
def clean_backtrace(*args)
if backtrace_cleaner
- backtrace_cleaner.clean(@exception.backtrace, *args)
+ backtrace_cleaner.clean(backtrace, *args)
else
- @exception.backtrace
+ backtrace
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index e90f8b9ce6..a7f95150a4 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -79,7 +79,7 @@ module ActionDispatch
class FlashHash
include Enumerable
- def self.from_session_value(value)
+ def self.from_session_value(value) #:nodoc:
flash = case value
when FlashHash # Rails 3.1, 3.2
new(value.instance_variable_get(:@flashes), value.instance_variable_get(:@used))
@@ -91,8 +91,11 @@ module ActionDispatch
flash.tap(&:sweep)
end
-
- def to_session_value
+
+ # Builds a hash containing the discarded values and the hashes
+ # representing the flashes.
+ # If there are no values in @flashes, returns nil.
+ def to_session_value #:nodoc:
return nil if empty?
{'discard' => @discard.to_a, 'flashes' => @flashes}
end
@@ -132,7 +135,7 @@ module ActionDispatch
end
def key?(name)
- @flashes.key? name
+ @flashes.key? name.to_s
end
def delete(key)
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index b426183488..29d43faeed 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -47,7 +47,7 @@ module ActionDispatch
else
false
end
- rescue Exception => e # JSON or Ruby code block errors
+ rescue => e # JSON or Ruby code block errors
logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise ParseError.new(e.message, e)
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index e66c21ef85..002bf8b11a 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -24,9 +24,19 @@ module ActionDispatch
path = URI.parser.unescape(path)
return false unless path.valid_encoding?
- paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
+ paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
+ Rack::Utils.clean_path_info v
+ }
- if match = paths.detect {|p| File.file?(File.join(@root, p)) }
+ if match = paths.detect { |p|
+ path = File.join(@root, p)
+ begin
+ File.file?(path) && File.readable?(path)
+ rescue SystemCallError
+ false
+ end
+
+ }
return ::Rack::Utils.escape(match)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
index db219c8fa9..49b1e83551 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
@@ -5,20 +5,8 @@
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
<% end %>
-<%
- clean_params = @request.filtered_parameters.clone
- clean_params.delete("action")
- clean_params.delete("controller")
-
- request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
-
- def debug_hash(object)
- object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
- end unless self.class.method_defined?(:debug_hash)
-%>
-
<h2 style="margin-top: 30px">Request</h2>
-<p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
+<p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
<div class="details">
<div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
@@ -31,4 +19,4 @@
</div>
<h2 style="margin-top: 30px">Response</h2>
-<p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre>
+<p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
index 51660a619b..e7b913bbe4 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
@@ -1,29 +1,27 @@
-<% if @source_extract %>
- <% @source_extract.each_with_index do |extract_source, index| %>
- <% if extract_source[:code] %>
- <div class="source <%="hidden" if index != 0%>" id="frame-source-<%=index%>">
- <div class="info">
- Extracted source (around line <strong>#<%= extract_source[:line_number] %></strong>):
- </div>
- <div class="data">
- <table cellpadding="0" cellspacing="0" class="lines">
- <tr>
- <td>
- <pre class="line_numbers">
- <% extract_source[:code].keys.each do |line_number| %>
+<% @source_extracts.each_with_index do |source_extract, index| %>
+ <% if source_extract[:code] %>
+ <div class="source <%="hidden" if @show_source_idx != index%>" id="frame-source-<%=index%>">
+ <div class="info">
+ Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>):
+ </div>
+ <div class="data">
+ <table cellpadding="0" cellspacing="0" class="lines">
+ <tr>
+ <td>
+ <pre class="line_numbers">
+ <% source_extract[:code].each_key do |line_number| %>
<span><%= line_number -%></span>
- <% end %>
- </pre>
- </td>
+ <% end %>
+ </pre>
+ </td>
<td width="100%">
<pre>
-<% extract_source[:code].each do |line, source| -%><div class="line<%= " active" if line == extract_source[:line_number] -%>"><%= source -%></div><% end -%>
+<% source_extract[:code].each do |line, source| -%><div class="line<%= " active" if line == source_extract[:line_number] -%>"><%= source -%></div><% end -%>
</pre>
</td>
- </tr>
- </table>
- </div>
+ </tr>
+ </table>
</div>
- <% end %>
+ </div>
<% end %>
<% end %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
index f62caf51d7..ab57b11c7d 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
@@ -12,7 +12,7 @@
<% end %>
<% @traces.each do |name, trace| %>
- <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
+ <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == @trace_to_show) ? 'block' : 'none' %>;">
<pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre>
</div>
<% end %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb
index 5c016e544e..2a65fd06ad 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb
@@ -4,4 +4,8 @@
<div id="container">
<h2><%= h @exception.message %></h2>
+
+ <%= render template: "rescues/_source" %>
+ <%= render template: "rescues/_trace" %>
+ <%= render template: "rescues/_request_and_response" %>
</div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb
index 7e9cedb95e..55dd5ddc7b 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb
@@ -27,4 +27,6 @@
<%= @routes_inspector.format(ActionDispatch::Routing::HtmlTableFormatter.new(self)) %>
<% end %>
+
+ <%= render template: "rescues/_request_and_response" %>
</div>
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 6ffa242da4..5cee0b5932 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
@@ -1,6 +1,6 @@
<% content_for :style do %>
#route_table {
- margin: 0 auto 0;
+ margin: 0;
border-collapse: collapse;
}
diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb
index 9d4f1aa3c5..1c9371d89c 100644
--- a/actionpack/lib/action_dispatch/request/utils.rb
+++ b/actionpack/lib/action_dispatch/request/utils.rb
@@ -16,10 +16,6 @@ module ActionDispatch
when Array
v.grep(Hash) { |x| deep_munge(x, keys) }
v.compact!
- if v.empty?
- hash[k] = nil
- ActiveSupport::Notifications.instrument("deep_munge.action_controller", keys: keys)
- end
when Hash
deep_munge(v, keys)
end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index ea3b2f419d..df5ebb6751 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -48,7 +48,7 @@ module ActionDispatch
def reqs
@reqs ||= begin
reqs = endpoint
- reqs += " #{constraints.to_s}" unless constraints.empty?
+ reqs += " #{constraints}" unless constraints.empty?
reqs
end
end
@@ -114,9 +114,7 @@ module ActionDispatch
def collect_routes(routes)
routes.collect do |route|
RouteWrapper.new(route)
- end.reject do |route|
- route.internal?
- end.collect do |route|
+ end.reject(&:internal?).collect do |route|
collect_engine_routes(route)
{ name: route.name,
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index fc28740828..b9e916078c 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -4,6 +4,7 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
+require 'active_support/core_ext/string/filters'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
require 'action_dispatch/routing/endpoint'
@@ -243,12 +244,10 @@ module ActionDispatch
def app(blocks)
if to.respond_to?(:call)
Constraints.new(to, blocks, false)
+ elsif blocks.any?
+ Constraints.new(dispatcher(defaults), blocks, true)
else
- if blocks.any?
- Constraints.new(dispatcher(defaults), blocks, true)
- else
- dispatcher(defaults)
- end
+ dispatcher(defaults)
end
end
@@ -282,11 +281,19 @@ module ActionDispatch
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}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a symbol is deprecated.
+ Please change `to: :#{to}` to `action: :#{to}`.
+ MSG
+
[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}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a controller without an action is deprecated.
+ Please change `to: :#{to}` to `controller: :#{to}`.
+ MSG
+
[to, nil]
else
[]
@@ -382,7 +389,7 @@ module ActionDispatch
# Matches a url pattern to one or more routes.
#
- # You should not use the `match` method in your router
+ # You should not use the +match+ method in your router
# without specifying an HTTP method.
#
# If you want to expose your action to both GET and POST, use:
@@ -393,7 +400,7 @@ module ActionDispatch
# Note that +:controller+, +:action+ and +:id+ are interpreted as url
# query parameters and thus available through +params+ in an action.
#
- # If you want to expose your action to GET, use `get` in the router:
+ # If you want to expose your action to GET, use +get+ in the router:
#
# Instead of:
#
@@ -434,7 +441,7 @@ module ActionDispatch
#
# Because requesting various HTTP verbs with a single action has security
# implications, you must either specify the actions in
- # the via options or use one of the HtttpHelpers[rdoc-ref:HttpHelpers]
+ # the via options or use one of the HttpHelpers[rdoc-ref:HttpHelpers]
# instead +match+
#
# === Options
@@ -448,7 +455,7 @@ module ActionDispatch
# The route's action.
#
# [:param]
- # Overrides the default resource identifier `:id` (name of the
+ # 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>.
@@ -573,13 +580,7 @@ module ActionDispatch
raise "A rack application must be specified" unless path
rails_app = rails_app? app
-
- if rails_app
- options[:as] ||= app.railtie_name
- else
- # non rails apps can't have an :as
- options[:as] = nil
- end
+ options[:as] ||= app_name(app, rails_app)
target_as = name_for_action(options[:as], path)
options[:via] ||= :all
@@ -611,6 +612,15 @@ module ActionDispatch
app.is_a?(Class) && app < Rails::Railtie
end
+ def app_name(app, rails_app)
+ if rails_app
+ app.railtie_name
+ elsif app.is_a?(Class)
+ class_name = app.name
+ ActiveSupport::Inflector.underscore(class_name).tr("/", "_")
+ end
+ end
+
def define_generate_prefix(app, name)
_route = @set.named_routes.get name
_routes = @set
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index f15868d37e..2e116ea9cd 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -1,5 +1,3 @@
-require 'action_controller/model_naming'
-
module ActionDispatch
module Routing
# Polymorphic URL helpers are methods for smart resolution to a named route call when
@@ -55,8 +53,6 @@ module ActionDispatch
# form_for([blog, @post]) # => "/blog/posts/1"
#
module PolymorphicRoutes
- include ActionController::ModelNaming
-
# Constructs a call to a named RESTful route for the given record and returns the
# resulting URL string. For example:
#
@@ -116,7 +112,6 @@ module ActionDispatch
action,
type,
opts
-
end
# Returns the path component of a URL for the given record. It uses
@@ -159,8 +154,7 @@ module ActionDispatch
end
def polymorphic_path_for_action(action, record_or_hash, options)
- options = options.merge(:action => action, :routing_type => :path)
- polymorphic_path(record_or_hash, options)
+ polymorphic_path(record_or_hash, options.merge(:action => action))
end
class HelperMethodBuilder # :nodoc:
@@ -253,7 +247,7 @@ module ActionDispatch
args = []
model = record.to_model
- name = if record.persisted?
+ name = if model.persisted?
args << model
model.model_name.singular_route_key
else
@@ -296,11 +290,12 @@ module ActionDispatch
when Class
@key_strategy.call record.model_name
else
- if record.persisted?
- args << record.to_model
- record.to_model.model_name.singular_route_key
+ model = record.to_model
+ if model.persisted?
+ args << model
+ model.model_name.singular_route_key
else
- @key_strategy.call record.to_model.model_name
+ @key_strategy.call model.model_name
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index f51bee3b31..d7693bdcee 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/string/filters'
require 'action_controller/metal/exceptions'
require 'action_dispatch/http/request'
require 'action_dispatch/routing/endpoint'
@@ -102,7 +103,10 @@ module ActionDispatch
end
def helpers
- ActiveSupport::Deprecation.warn("`named_routes.helpers` is deprecated, please use `route_defined?(route_name)` to see if a named route was defined.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `named_routes.helpers` is deprecated, please use `route_defined?(route_name)`
+ to see if a named route was defined.
+ MSG
@path_helpers + @url_helpers
end
@@ -134,8 +138,8 @@ module ActionDispatch
@url_helpers_module.send :undef_method, url_name
end
routes[key] = route
- define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
- define_url_helper @url_helpers_module, route, url_name, route.defaults, name, FULL
+ define_url_helper @path_helpers_module, route, path_name, route.defaults, name, LEGACY
+ define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
@path_helpers << path_name
@url_helpers << url_name
@@ -267,7 +271,7 @@ module ActionDispatch
controller_options = t.url_options
options = controller_options.merge @options
hash = handle_positional_args(controller_options,
- inner_options || {},
+ deprecate_string_options(inner_options) || {},
args,
options,
@segment_keys)
@@ -276,19 +280,41 @@ module ActionDispatch
end
def handle_positional_args(controller_options, inner_options, args, result, path_params)
-
if args.size > 0
- if args.size < path_params.size - 1 # take format into account
+ # take format into account
+ if path_params.include?(:format)
+ path_params_size = path_params.size - 1
+ else
+ path_params_size = path_params.size
+ end
+
+ if args.size < path_params_size
path_params -= controller_options.keys
path_params -= result.keys
end
path_params.each { |param|
- result[param] = inner_options[param] || args.shift
+ result[param] = inner_options.fetch(param) { args.shift }
}
end
result.merge!(inner_options)
end
+
+ DEPRECATED_STRING_OPTIONS = %w[controller action]
+
+ def deprecate_string_options(options)
+ options ||= {}
+ deprecated_string_options = options.keys & DEPRECATED_STRING_OPTIONS
+ if deprecated_string_options.any?
+ msg = "Calling URL helpers with string keys #{deprecated_string_options.join(", ")} is deprecated. Use symbols instead."
+ ActiveSupport::Deprecation.warn(msg)
+ deprecated_string_options.each do |option|
+ value = options.delete(option)
+ options[option.to_sym] = value
+ end
+ end
+ options
+ end
end
private
@@ -322,6 +348,32 @@ module ActionDispatch
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
+ LEGACY = ->(options) {
+ if options.key?(:only_path)
+ if options[:only_path]
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `true`. This option will stop working on
+ path helpers in Rails 5. Simply remove the `only_path: true`
+ argument from your call as it is redundant when applied to a
+ path helper.
+ MSG
+
+ PATH.call(options)
+ else
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `false`. This option will stop working on
+ path helpers in Rails 5. Use the corresponding `*_url` helper
+ instead.
+ MSG
+
+ FULL.call(options)
+ end
+ else
+ PATH.call(options)
+ end
+ }
# :startdoc:
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
@@ -427,7 +479,7 @@ module ActionDispatch
RUBY
end
- def url_helpers(include_path_helpers = true)
+ def url_helpers(supports_path = true)
routes = self
Module.new do
@@ -454,7 +506,7 @@ module ActionDispatch
# named routes...
include url_helpers
- if include_path_helpers
+ if supports_path
path_helpers = routes.named_routes.path_helpers_module
else
path_helpers = routes.named_routes.path_helpers_module(true)
@@ -472,6 +524,12 @@ module ActionDispatch
# UrlFor (included in this module) add extra
# conveniences for working with @_routes.
define_method(:_routes) { @_routes || routes }
+
+ define_method(:_generate_paths_by_default) do
+ supports_path
+ end
+
+ private :_generate_paths_by_default
end
end
@@ -493,7 +551,7 @@ module ActionDispatch
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 })
+ conditions = build_conditions(conditions, path.names.map(&:to_sym))
route = @set.add_route(app, path, conditions, defaults, name)
named_routes[name] = route if name
@@ -555,7 +613,7 @@ module ActionDispatch
if name == :controller
value
elsif value.is_a?(Array)
- value.map { |v| v.to_param }.join('/')
+ value.map(&:to_param).join('/')
elsif param = value.to_param
param
end
@@ -699,7 +757,7 @@ module ActionDispatch
end
def find_script_name(options)
- options.delete(:script_name) { '' }
+ options.delete(:script_name) || ''
end
def path_for(options, route_name = nil) # :nodoc:
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index eb554ec383..dca86858cc 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -184,6 +184,12 @@ module ActionDispatch
def _routes_context
self
end
+
+ private
+
+ def _generate_paths_by_default
+ true
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index e06f7037c6..28dc88d317 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -144,12 +144,6 @@ module ActionDispatch
old_controller, @controller = @controller, @controller.clone
_routes = @routes
- # Unfortunately, there is currently an abstraction leak between AC::Base
- # and AV::Base which requires having the URL helpers in both AC and AV.
- # To do this safely at runtime for tests, we need to bump up the helper serial
- # to that the old AV subclass isn't cached.
- #
- # TODO: Make this unnecessary
@controller.singleton_class.send(:include, _routes.url_helpers)
@controller.view_context_class = Class.new(@controller.view_context_class) do
include _routes.url_helpers
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index 19eca60f70..7361e6c44b 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -1,3 +1,3 @@
require 'active_support/deprecation'
-ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been has been extracted to the rails-dom-testing gem.") \ No newline at end of file
+ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been extracted to the rails-dom-testing gem.")
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index d5348d80e1..da98b1d6ce 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -1,3 +1,3 @@
require 'active_support/deprecation'
-ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been has been extracted to the rails-dom-testing gem.")
+ActiveSupport::Deprecation.warn('`ActionDispatch::Assertions::TagAssertions` has been extracted to the rails-dom-testing gem.')
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 2d1c3ac5c7..f0e2c5becc 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -326,13 +326,21 @@ module ActionDispatch
@integration_session = Integration::Session.new(app)
end
+ def remove! # :nodoc:
+ @integration_session = nil
+ end
+
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
reset! unless integration_session
- reset_template_assertion
- # reset the html_document variable, but only for new get/post calls
- @html_document = nil unless method == 'cookies' || method == 'assigns'
+
+ # reset the html_document variable, except for cookies/assigns calls
+ unless method == 'cookies' || method == 'assigns'
+ @html_document = nil
+ reset_template_assertion
+ end
+
integration_session.__send__(method, *args).tap do
copy_session_variables!
end
@@ -472,6 +480,84 @@ module ActionDispatch
# end
# end
# end
+ #
+ # Another longer example would be:
+ #
+ # A simple integration test that exercises multiple controllers:
+ #
+ # require 'test_helper'
+ #
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
+ # test "login and browse site" do
+ # # login via https
+ # https!
+ # get "/login"
+ # assert_response :success
+ #
+ # post_via_redirect "/login", username: users(:david).username, password: users(:david).password
+ # assert_equal '/welcome', path
+ # assert_equal 'Welcome david!', flash[:notice]
+ #
+ # https!(false)
+ # get "/articles/all"
+ # assert_response :success
+ # assert assigns(:articles)
+ # end
+ # end
+ #
+ # As you can see the integration test involves multiple controllers and
+ # exercises the entire stack from database to dispatcher. In addition you can
+ # have multiple session instances open simultaneously in a test and extend
+ # those instances with assertion methods to create a very powerful testing
+ # DSL (domain-specific language) just for your application.
+ #
+ # Here's an example of multiple sessions and custom DSL in an integration test
+ #
+ # require 'test_helper'
+ #
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
+ # test "login and browse site" do
+ # # User david logs in
+ # david = login(:david)
+ # # User guest logs in
+ # guest = login(:guest)
+ #
+ # # Both are now available in different sessions
+ # assert_equal 'Welcome david!', david.flash[:notice]
+ # assert_equal 'Welcome guest!', guest.flash[:notice]
+ #
+ # # User david can browse site
+ # david.browses_site
+ # # User guest can browse site as well
+ # guest.browses_site
+ #
+ # # Continue with other assertions
+ # end
+ #
+ # private
+ #
+ # module CustomDsl
+ # def browses_site
+ # get "/products/all"
+ # assert_response :success
+ # assert assigns(:products)
+ # end
+ # end
+ #
+ # def login(user)
+ # open_session do |sess|
+ # sess.extend(CustomDsl)
+ # u = users(user)
+ # sess.https!
+ # sess.post "/login", username: u.username, password: u.password
+ # assert_equal '/welcome', sess.path
+ # sess.https!(false)
+ # end
+ # end
+ # end
+ #
+ # Consult the Rails Testing Guide for more.
+
class IntegrationTest < ActiveSupport::TestCase
include Integration::Runner
include ActionController::TemplateAssertions
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index de3dc5f924..4b9a088265 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -60,7 +60,7 @@ module ActionDispatch
def accept=(mime_types)
@env.delete('action_dispatch.request.accepts')
- @env['HTTP_ACCEPT'] = Array(mime_types).collect { |mime_type| mime_type.to_s }.join(",")
+ @env['HTTP_ACCEPT'] = Array(mime_types).collect(&:to_s).join(",")
end
alias :rack_cookies :cookies
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index 280d35adcb..255ac9f4ed 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -5,10 +5,10 @@ module ActionPack
end
module VERSION
- MAJOR = 4
- MINOR = 2
+ MAJOR = 5
+ MINOR = 0
TINY = 0
- PRE = "beta1"
+ PRE = "alpha"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 799c17119d..2d69ceed3a 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -21,6 +21,7 @@ PROCESS_COUNT = (ENV['N'] || 4).to_i
require 'active_support/testing/autorun'
require 'abstract_controller'
+require 'abstract_controller/railties/routes_helpers'
require 'action_controller'
require 'action_view'
require 'action_view/testing/resolvers'
@@ -53,7 +54,7 @@ I18n.enforce_available_locales = false
# Register danish language for testing
I18n.backend.store_translations 'da', {}
I18n.backend.store_translations 'pt-BR', {}
-ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort
+ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
@@ -194,6 +195,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
yield temporary_routes
ensure
self.class.app = old_app
+ self.remove!
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end
@@ -259,7 +261,7 @@ end
module ActionController
class Base
# This stub emulates the Railtie including the URL helpers from a Rails application
- include SharedTestRoutes.url_helpers
+ extend AbstractController::Railties::RoutesHelpers.with(SharedTestRoutes)
include SharedTestRoutes.mounted_helpers
self.view_paths = FIXTURE_LOAD_PATH
@@ -516,4 +518,4 @@ end
# FIXME: we have tests that depend on run order, we should fix that and
# remove this method call.
require 'active_support/test_case'
-ActiveSupport::TestCase.my_tests_are_order_dependent!
+ActiveSupport::TestCase.test_order = :sorted
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index f2a4503f13..d0dfbfbc74 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -575,6 +575,13 @@ class AssertTemplateTest < ActionController::TestCase
end
end
+ def test_fails_expecting_not_known_layout
+ get :render_with_layout
+ assert_raise(ArgumentError) do
+ assert_template :layout => 1
+ end
+ end
+
def test_passes_with_correct_layout
get :render_with_layout
assert_template :layout => "layouts/standard"
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index b2b01b3fa9..2e08a6af9f 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -10,7 +10,7 @@ class ActionController::Base
def before_actions
filters = _process_action_callbacks.select { |c| c.kind == :before }
- filters.map! { |c| c.raw_filter }
+ filters.map!(&:raw_filter)
end
end
@@ -504,7 +504,6 @@ class FilterTest < ActionController::TestCase
def non_yielding_action
@filters << "it didn't yield"
- @filter_return_value
end
def action_three
@@ -528,32 +527,15 @@ class FilterTest < ActionController::TestCase
end
end
- def test_non_yielding_around_actions_not_returning_false_do_not_raise
+ def test_non_yielding_around_actions_do_not_raise
controller = NonYieldingAroundFilterController.new
- controller.instance_variable_set "@filter_return_value", true
assert_nothing_raised do
test_process(controller, "index")
end
end
- 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
- test_process(controller, "index")
- end
- end
-
- 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_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
@@ -1021,21 +1003,21 @@ class YieldingAroundFiltersTest < ActionController::TestCase
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 '', response.body
assert_equal 1, controller.instance_variable_get(:@try)
end
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 '', response.body
assert_equal 2, controller.instance_variable_get(:@try)
end
def test_last_action_in_multiple_before_action_chain_halts
controller = ::FilterTest::TestMultipleFiltersController.new
response = test_process(controller, 'fail_3')
- assert_equal ' ', response.body
+ assert_equal '', response.body
assert_equal 3, controller.instance_variable_get(:@try)
end
diff --git a/actionpack/test/controller/flash_hash_test.rb b/actionpack/test/controller/flash_hash_test.rb
index 50b36a0567..d979b561f2 100644
--- a/actionpack/test/controller/flash_hash_test.rb
+++ b/actionpack/test/controller/flash_hash_test.rb
@@ -29,6 +29,15 @@ module ActionDispatch
assert_equal 'world', @hash['hello']
end
+ def test_key
+ @hash['foo'] = 'bar'
+
+ assert @hash.key?('foo')
+ assert @hash.key?(:foo)
+ assert_not @hash.key?('bar')
+ assert_not @hash.key?(:bar)
+ end
+
def test_delete
@hash['foo'] = 'bar'
@hash.delete 'foo'
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index 20f99f19ee..936b8c2450 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -60,6 +60,12 @@ class HelpersPathsController < ActionController::Base
end
end
+class HelpersTypoController < ActionController::Base
+ path = File.expand_path('../../fixtures/helpers_typo', __FILE__)
+ $:.unshift(path)
+ self.helpers_path = path
+end
+
module LocalAbcHelper
def a() end
def b() end
@@ -82,6 +88,22 @@ class HelperPathsTest < ActiveSupport::TestCase
end
end
+class HelpersTypoControllerTest < ActiveSupport::TestCase
+ def setup
+ @autoload_paths = ActiveSupport::Dependencies.autoload_paths
+ ActiveSupport::Dependencies.autoload_paths = Array(HelpersTypoController.helpers_path)
+ end
+
+ def test_helper_typo_error_message
+ e = assert_raise(NameError) { HelpersTypoController.helper 'admin/users' }
+ assert_equal "Couldn't find Admin::UsersHelper, expected it to be defined in helpers/admin/users_helper.rb", e.message
+ end
+
+ def teardown
+ ActiveSupport::Dependencies.autoload_paths = @autoload_paths
+ end
+end
+
class HelperTest < ActiveSupport::TestCase
class TestController < ActionController::Base
attr_accessor :delegate_attr
diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb
index 8c6c8a0aa7..a758df2ec6 100644
--- a/actionpack/test/controller/http_token_authentication_test.rb
+++ b/actionpack/test/controller/http_token_authentication_test.rb
@@ -162,17 +162,36 @@ class HttpTokenAuthenticationTest < ActionController::TestCase
assert_equal(expected, actual)
end
+ test "token_and_options returns right token when token key is not specified in header" do
+ token = "rcHu+HzSFw89Ypyhn/896A="
+
+ actual = ActionController::HttpAuthentication::Token.token_and_options(
+ sample_request_without_token_key(token)
+ ).first
+
+ expected = token
+ 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
+ mock_authorization_request(authorization)
end
def malformed_request
- @malformed_request ||= OpenStruct.new authorization: %{Token token=}
+ mock_authorization_request(%{Token token=})
+ end
+
+ def sample_request_without_token_key(token)
+ mock_authorization_request(%{Token #{token}})
+ end
+
+ def mock_authorization_request(authorization)
+ OpenStruct.new(authorization: authorization)
end
def encode_credentials(token, options = {})
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 99b53e6fd2..d6219b7626 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -615,6 +615,8 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
get 'bar', :to => 'application_integration_test/test#index', :as => :bar
mount MountedApp => '/mounted', :as => "mounted"
+ get 'fooz' => proc { |env| [ 200, {'X-Cascade' => 'pass'}, [ "omg" ] ] }, :anchor => false
+ get 'fooz', :to => 'application_integration_test/test#index'
end
def app
@@ -631,6 +633,12 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
assert_equal '/mounted/baz', mounted.baz_path
end
+ test "path after cascade pass" do
+ get '/fooz'
+ assert_equal 'index', response.body
+ assert_equal '/fooz', path
+ end
+
test "route helpers after controller access" do
get '/'
assert_equal '/', empty_string_path
@@ -806,3 +814,39 @@ class HeadWithStatusActionIntegrationTest < ActionDispatch::IntegrationTest
assert_response :ok
end
end
+
+class IntegrationWithRoutingTest < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def index
+ render plain: 'ok'
+ end
+ end
+
+ def test_with_routing_resets_session
+ klass_namespace = self.class.name.underscore
+
+ with_routing do |routes|
+ routes.draw do
+ namespace klass_namespace do
+ resources :foo, path: '/with'
+ end
+ end
+
+ get '/integration_with_routing_test/with'
+ assert_response 200
+ assert_equal 'ok', response.body
+ end
+
+ with_routing do |routes|
+ routes.draw do
+ namespace klass_namespace do
+ resources :foo, path: '/routing'
+ end
+ end
+
+ get '/integration_with_routing_test/routing'
+ assert_response 200
+ assert_equal 'ok', response.body
+ end
+ end
+end
diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb
index 27871ef351..2be947c648 100644
--- a/actionpack/test/controller/localized_templates_test.rb
+++ b/actionpack/test/controller/localized_templates_test.rb
@@ -19,7 +19,7 @@ class LocalizedTemplatesTest < ActionController::TestCase
def test_localized_template_is_used
I18n.locale = :de
get :hello_world
- assert_equal "Gutten Tag", @response.body
+ assert_equal "Guten Tag", @response.body
end
def test_default_locale_template_is_used_when_locale_is_missing
@@ -34,7 +34,7 @@ class LocalizedTemplatesTest < ActionController::TestCase
I18n.fallbacks[:"de-AT"] = [:de]
get :hello_world
- assert_equal "Gutten Tag", @response.body
+ assert_equal "Guten Tag", @response.body
end
def test_localized_template_has_correct_header_with_no_format_in_template_name
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 1bc7ad3015..66d2fd7716 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -579,10 +579,10 @@ class RespondToControllerTest < ActionController::TestCase
end
get :using_defaults
- assert_equal "using_defaults - #{[:html].to_s}", @response.body
+ assert_equal "using_defaults - #{[:html]}", @response.body
get :using_defaults, :format => "xml"
- assert_equal "using_defaults - #{[:xml].to_s}", @response.body
+ assert_equal "using_defaults - #{[:xml]}", @response.body
end
def test_format_with_custom_response_type
diff --git a/actionpack/test/controller/new_base/render_file_test.rb b/actionpack/test/controller/new_base/render_file_test.rb
index a961cbf849..0c21bb0719 100644
--- a/actionpack/test/controller/new_base/render_file_test.rb
+++ b/actionpack/test/controller/new_base/render_file_test.rb
@@ -13,15 +13,6 @@ module RenderFile
render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
end
- def without_file_key
- render File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world])
- end
-
- def without_file_key_with_instance_variable
- @secret = 'in the sauce'
- render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
- end
-
def relative_path
@secret = 'in the sauce'
render :file => '../../fixtures/test/render_file_with_ivar'
@@ -41,11 +32,6 @@ module RenderFile
path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals')
render :file => path, :locals => {:secret => 'in the sauce'}
end
-
- def without_file_key_with_locals
- path = FIXTURES.join('test/render_file_with_locals').to_s
- render path, :locals => {:secret => 'in the sauce'}
- end
end
class TestBasic < Rack::TestCase
@@ -61,16 +47,6 @@ module RenderFile
assert_response "The secret is in the sauce\n"
end
- test "rendering path without specifying the :file key" do
- get :without_file_key
- assert_response "Hello world!"
- end
-
- test "rendering path without specifying the :file key with ivar" do
- get :without_file_key_with_instance_variable
- assert_response "The secret is in the sauce\n"
- end
-
test "rendering a relative path" do
get :relative_path
assert_response "The secret is in the sauce\n"
@@ -90,10 +66,5 @@ module RenderFile
get :with_locals
assert_response "The secret is in the sauce\n"
end
-
- test "rendering path without specifying the :file key with locals" do
- get :without_file_key_with_locals
- assert_response "The secret is in the sauce\n"
- end
end
end
diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb
index e87811776a..42a86b1d0d 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -45,6 +45,10 @@ module RenderTemplate
render :template => "locals", :locals => { :secret => 'area51' }
end
+ def with_locals_without_key
+ render "locals", :locals => { :secret => 'area51' }
+ end
+
def builder_template
render :template => "xml_template"
end
@@ -101,6 +105,11 @@ module RenderTemplate
assert_response "The secret is area51"
end
+ test "rendering a template with local variables without key" do
+ get :with_locals
+ assert_response "The secret is area51"
+ end
+
test "rendering a builder template" do
get :builder_template, "format" => "xml"
assert_response "<html>\n <p>Hello</p>\n</html>\n"
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index ba98ad7605..2ed486516d 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -280,4 +280,10 @@ class ParametersPermitTest < ActiveSupport::TestCase
assert_equal({ "controller" => "users", "action" => "create" }, params.to_h)
end
+
+ test "to_unsafe_h returns unfiltered params" do
+ assert @params.to_h.is_a? Hash
+ assert_not @params.to_h.is_a? ActionController::Parameters
+ assert_equal @params.to_hash, @params.to_unsafe_h
+ end
end
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index a5f43c4b6b..0e15883f43 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -43,11 +43,11 @@ class ResourcesTest < ActionController::TestCase
:member => member_methods,
:path_names => path_names do |options|
- collection_methods.keys.each do |action|
+ collection_methods.each_key do |action|
assert_named_route "/messages/#{path_names[action] || action}", "#{action}_messages_path", :action => action
end
- member_methods.keys.each do |action|
+ member_methods.each_key do |action|
assert_named_route "/messages/1/#{path_names[action] || action}", "#{action}_message_path", :action => action, :id => "1"
end
@@ -150,7 +150,7 @@ class ResourcesTest < ActionController::TestCase
end
assert_restful_named_routes_for :messages do |options|
- actions.keys.each do |action|
+ actions.each_key do |action|
assert_named_route "/messages/#{action}", "#{action}_messages_path", :action => action
end
end
@@ -180,7 +180,7 @@ class ResourcesTest < ActionController::TestCase
end
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
- actions.keys.each do |action|
+ actions.each_key do |action|
assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action
end
end
@@ -207,7 +207,7 @@ class ResourcesTest < ActionController::TestCase
end
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
- actions.keys.each do |action|
+ actions.each_key do |action|
assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action
end
end
@@ -237,7 +237,7 @@ class ResourcesTest < ActionController::TestCase
end
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
- actions.keys.each do |action|
+ actions.each_key do |action|
assert_named_route "/threads/1/messages/#{action}.xml", "#{action}_thread_messages_path", :action => action, :format => 'xml'
end
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index c18914cc8e..9caa5cbe57 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -884,13 +884,13 @@ class RouteSetTest < ActiveSupport::TestCase
set.draw { get ':controller/(:action(/:id))' }
path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
assert_equal "/foo/bar/15", path
- assert_equal %w(that this), extras.map { |e| e.to_s }.sort
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
def test_extra_keys
set.draw { get ':controller/:action/:id' }
extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal %w(that this), extras.map { |e| e.to_s }.sort
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
def test_generate_extras_not_first
@@ -900,7 +900,7 @@ class RouteSetTest < ActiveSupport::TestCase
end
path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
assert_equal "/foo/bar/15", path
- assert_equal %w(that this), extras.map { |e| e.to_s }.sort
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
def test_generate_not_first
@@ -918,7 +918,7 @@ class RouteSetTest < ActiveSupport::TestCase
get ':controller/:action/:id'
end
extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal %w(that this), extras.map { |e| e.to_s }.sort
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
def test_draw
@@ -1001,6 +1001,9 @@ class RouteSetTest < ActiveSupport::TestCase
assert_equal "http://test.host/people?baz=bar#location",
controller.send(:index_url, :baz => "bar", :anchor => 'location')
+
+ assert_equal "http://test.host/people", controller.send(:index_url, anchor: nil)
+ assert_equal "http://test.host/people", controller.send(:index_url, anchor: false)
end
def test_named_route_url_method_with_port
@@ -1383,7 +1386,7 @@ class RouteSetTest < ActiveSupport::TestCase
url = controller.url_for({ :controller => "connection", :only_path => true })
assert_equal "/connection/connection", url
- url = controller.url_for({ :use_route => :family_connection,
+ url = controller.url_for({ :use_route => "family_connection",
:controller => "connection", :only_path => true })
assert_equal "/connection", url
end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 1280e0d9a3..ba2ff7d12c 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'controller/fake_controllers'
require 'active_support/json/decoding'
+require 'rails/engine'
class TestCaseTest < ActionController::TestCase
class TestController < ActionController::Base
@@ -132,6 +133,14 @@ XML
render :nothing => true
end
+ def test_without_body
+ render html: '<div class="foo"></div>'.html_safe
+ end
+
+ def test_with_body
+ render html: '<body class="foo"></body>'.html_safe
+ end
+
private
def generate_url(opts)
@@ -179,6 +188,19 @@ XML
end
end
+ def test_assert_select_without_body
+ get :test_without_body
+
+ assert_select 'body', 0
+ assert_select 'div.foo'
+ end
+
+ def test_assert_select_with_body
+ get :test_with_body
+
+ assert_select 'body.foo'
+ end
+
def test_url_options_reset
@controller = DefaultUrlOptionsCachingController.new
get :test_url_options_reset
@@ -499,11 +521,23 @@ XML
end
end
+ def test_use_route
+ with_routing do |set|
+ set.draw do
+ get 'via_unnamed_route', to: 'test_case_test/test#test_uri'
+ get 'via_named_route', as: :a_named_route, to: 'test_case_test/test#test_uri'
+ end
+
+ assert_deprecated { get :test_uri, use_route: :a_named_route }
+ assert_equal '/via_named_route', @response.body
+ end
+ end
+
def test_assert_realistic_path_parameters
get :test_params, :id => 20, :foo => Object.new
# All elements of path_parameters should use Symbol keys
- @request.path_parameters.keys.each do |key|
+ @request.path_parameters.each_key do |key|
assert_kind_of Symbol, key
end
end
@@ -720,6 +754,57 @@ XML
end
end
+module EngineControllerTests
+ class Engine < ::Rails::Engine
+ isolate_namespace EngineControllerTests
+
+ routes.draw do
+ get '/' => 'bar#index'
+ end
+ end
+
+ class BarController < ActionController::Base
+ def index
+ render :text => 'bar'
+ end
+ end
+
+ class BarControllerTest < ActionController::TestCase
+ tests BarController
+
+ def test_engine_controller_route
+ get :index
+ assert_equal @response.body, 'bar'
+ end
+ end
+
+ class BarControllerTestWithExplicitRouteSet < ActionController::TestCase
+ tests BarController
+
+ def setup
+ @routes = Engine.routes
+ end
+
+ def test_engine_controller_route
+ get :index
+ assert_equal @response.body, 'bar'
+ end
+ end
+
+ class BarControllerTestWithHostApplicationRouteSet < ActionController::TestCase
+ tests BarController
+
+ def test_use_route
+ with_routing do |set|
+ set.draw { mount Engine => '/foo' }
+
+ assert_deprecated { get :index, use_route: :foo }
+ assert_equal @response.body, 'bar'
+ end
+ end
+ end
+end
+
class InferringClassNameTest < ActionController::TestCase
def test_determine_controller_class
assert_equal ContentController, determine_class("ContentControllerTest")
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 969129d9ba..0ffa2d2a03 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -25,8 +25,7 @@ module AbstractController
path = klass.new.fun_path({:controller => :articles,
:baz => "baz",
- :zot => "zot",
- :only_path => true })
+ :zot => "zot"})
# :bar key isn't provided
assert_equal '/foo/zot', path
end
@@ -55,6 +54,20 @@ module AbstractController
)
end
+ def test_nil_anchor
+ assert_equal(
+ '/c/a',
+ W.new.url_for(only_path: true, controller: 'c', action: 'a', anchor: nil)
+ )
+ end
+
+ def test_false_anchor
+ assert_equal(
+ '/c/a',
+ W.new.url_for(only_path: true, controller: 'c', action: 'a', anchor: false)
+ )
+ end
+
def test_anchor_should_call_to_param
assert_equal('/c/a#anchor',
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anchor'))
@@ -277,6 +290,13 @@ module AbstractController
end
end
+ def test_using_nil_script_name_properly_concats_with_original_script_name
+ add_host!
+ assert_equal('https://www.basecamphq.com/subdir/c/a/i',
+ W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => nil, :original_script_name => '/subdir')
+ )
+ end
+
def test_only_path
with_routing do |set|
set.draw do
@@ -291,7 +311,7 @@ module AbstractController
assert_equal '/brave/new/world',
controller.url_for(:controller => 'brave', :action => 'new', :id => 'world', :only_path => true)
- assert_equal("/home/sweet/home/alabama", controller.home_path(:user => 'alabama', :host => 'unused', :only_path => true))
+ assert_equal("/home/sweet/home/alabama", controller.home_path(:user => 'alabama', :host => 'unused'))
assert_equal("/home/sweet/home/alabama", controller.home_path('alabama'))
end
end
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index d80b0e2da0..2b109ff19e 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -83,6 +83,16 @@ class WebServiceTest < ActionDispatch::IntegrationTest
end
end
+ def test_parsing_json_doesnot_rescue_exception
+ with_test_route_set do
+ with_params_parsers Mime::JSON => Proc.new { |data| raise Interrupt } do
+ assert_raises(Interrupt) do
+ post "/", '{"title":"JSON"}}', 'CONTENT_TYPE' => 'application/json'
+ end
+ end
+ end
+ end
+
private
def with_params_parsers(parsers = {})
old_session = @integration_session
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 7dc6c37522..19a98a4054 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -1,12 +1,5 @@
require 'abstract_unit'
-
-begin
- require 'openssl'
- OpenSSL::PKCS5
-rescue LoadError, NameError
- $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install"
-else
-
+require 'openssl'
require 'active_support/key_generator'
require 'active_support/message_verifier'
@@ -152,11 +145,21 @@ class CookiesTest < ActionController::TestCase
head :ok
end
+ def set_cookie_with_domain_all_as_string
+ cookies[:user_name] = {:value => "rizwanreza", :domain => 'all'}
+ head :ok
+ end
+
def delete_cookie_with_domain
cookies.delete(:user_name, :domain => :all)
head :ok
end
+ def delete_cookie_with_domain_all_as_string
+ cookies.delete(:user_name, :domain => 'all')
+ head :ok
+ end
+
def set_cookie_with_domain_and_tld
cookies[:user_name] = {:value => "rizwanreza", :domain => :all, :tld_length => 2}
head :ok
@@ -494,7 +497,7 @@ class CookiesTest < ActionController::TestCase
assert_nil @response.cookies["user_id"]
end
- def test_accessing_nonexistant_signed_cookie_should_not_raise_an_invalid_signature
+ def test_accessing_nonexistent_signed_cookie_should_not_raise_an_invalid_signature
get :set_signed_cookie
assert_nil @controller.send(:cookies).signed[:non_existant_attribute]
end
@@ -612,7 +615,7 @@ class CookiesTest < ActionController::TestCase
assert_nil @response.cookies["foo"]
end
- def test_accessing_nonexistant_encrypted_cookie_should_not_raise_invalid_message
+ def test_accessing_nonexistent_encrypted_cookie_should_not_raise_invalid_message
get :set_encrypted_cookie
assert_nil @controller.send(:cookies).encrypted[:non_existant_attribute]
end
@@ -1155,5 +1158,3 @@ class CookiesTest < ActionController::TestCase
end
end
end
-
-end
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 0add9fa3b0..1e5ed60b09 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -19,6 +19,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@closed = true
end
+ def method_that_raises
+ raise StandardError.new 'error in framework'
+ end
+
def call(env)
env['action_dispatch.show_detailed_exceptions'] = @detailed
req = ActionDispatch::Request.new(env)
@@ -39,6 +43,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
raise ActionController::InvalidAuthenticityToken
when "/not_found_original_exception"
raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
+ when "/missing_template"
+ raise ActionView::MissingTemplate.new(%w(foo), 'foo/index', %w(foo), false, 'mailer')
when "/bad_request"
raise ActionController::BadRequest
when "/missing_keys"
@@ -57,7 +63,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
{})
raise ActionView::Template::Error.new(template, e)
end
-
+ when "/framework_raises"
+ method_that_raises
else
raise "puke!"
end
@@ -115,6 +122,15 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_no_match '&lt;|&gt;', routing_table, "there should not be escaped html in the output"
end
+ test 'displays request and response info when a RoutingError occurs' do
+ @app = DevelopmentApp
+
+ get "/pass", {}, {'action_dispatch.show_exceptions' => true}
+
+ assert_select 'h2', /Request/
+ assert_select 'h2', /Response/
+ end
+
test "rescue with diagnostics message" do
@app = DevelopmentApp
@@ -225,6 +241,29 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_match(/RuntimeError\n\s+in FeaturedTileController/, body)
end
+ test "show formatted params" do
+ @app = DevelopmentApp
+
+ params = {
+ 'id' => 'unknown',
+ 'someparam' => {
+ 'foo' => 'bar',
+ 'abc' => 'goo'
+ }
+ }
+
+ get("/runtime_error", {}, {
+ 'action_dispatch.show_exceptions' => true,
+ 'action_dispatch.request.parameters' => {
+ 'action' => 'show',
+ 'controller' => 'featured_tile'
+ }.merge(params)
+ })
+ assert_response 500
+
+ assert_includes(body, CGI.escapeHTML(PP.pp(params, "", 200)))
+ end
+
test "sets the HTTP charset parameter" do
@app = DevelopmentApp
@@ -270,6 +309,22 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
end
+ test 'display backtrace on template missing errors' do
+ @app = DevelopmentApp
+
+ get "/missing_template", nil, {}
+
+ assert_select "header h1", /Template is missing/
+
+ assert_select "#container h2", /^Missing template/
+
+ assert_select '#Application-Trace'
+ assert_select '#Framework-Trace'
+ assert_select '#Full-Trace'
+
+ assert_select 'h2', /Request/
+ end
+
test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do
@app = DevelopmentApp
@@ -280,4 +335,39 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
end
end
+
+ test 'debug exceptions app shows user code that caused the error in source view' do
+ @app = DevelopmentApp
+ Rails.stubs(:root).returns(Pathname.new('.'))
+ cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
+ bc.add_silencer { |line| line =~ /method_that_raises/ }
+ bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ end
+
+ get '/framework_raises', {}, {'action_dispatch.backtrace_cleaner' => cleaner}
+
+ # Assert correct error
+ assert_response 500
+ assert_select 'h2', /error in framework/
+
+ # assert source view line is the call to method_that_raises
+ assert_select 'div.source:not(.hidden)' do
+ assert_select 'pre .line.active', /method_that_raises/
+ end
+
+ # assert first source view (hidden) that throws the error
+ assert_select 'div.source:first' do
+ assert_select 'pre .line.active', /raise StandardError\.new/
+ end
+
+ # assert application trace refers to line that calls method_that_raises is first
+ assert_select '#Application-Trace' do
+ assert_select 'pre code a:first', %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call}
+ end
+
+ # assert framework trace that that threw the error is first
+ assert_select '#Framework-Trace' do
+ assert_select 'pre code a:first', /method_that_raises/
+ end
+ end
end
diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb
new file mode 100644
index 0000000000..d7408164ba
--- /dev/null
+++ b/actionpack/test/dispatch/exception_wrapper_test.rb
@@ -0,0 +1,97 @@
+require 'abstract_unit'
+
+module ActionDispatch
+ class ExceptionWrapperTest < ActionDispatch::IntegrationTest
+ class TestError < StandardError
+ attr_reader :backtrace
+
+ def initialize(*backtrace)
+ @backtrace = backtrace.flatten
+ end
+ end
+
+ class BadlyDefinedError < StandardError
+ def backtrace
+ nil
+ end
+ end
+
+ setup do
+ Rails.stubs(:root).returns(Pathname.new('.'))
+
+ cleaner = ActiveSupport::BacktraceCleaner.new
+ cleaner.add_silencer { |line| line !~ /^lib/ }
+
+ @environment = { 'action_dispatch.backtrace_cleaner' => cleaner }
+ end
+
+ test '#source_extracts fetches source fragments for every backtrace entry' do
+ exception = TestError.new("lib/file.rb:42:in `index'")
+ wrapper = ExceptionWrapper.new({}, exception)
+
+ wrapper.expects(:source_fragment).with('lib/file.rb', 42).returns('foo')
+
+ assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts
+ end
+
+
+ test '#application_trace returns traces only from the application' do
+ exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'"))
+ wrapper = ExceptionWrapper.new(@environment, exception)
+
+ assert_equal [ "lib/file.rb:42:in `index'" ], wrapper.application_trace
+ end
+
+ test '#application_trace cannot be nil' do
+ nil_backtrace_wrapper = ExceptionWrapper.new(@environment, BadlyDefinedError.new)
+ nil_cleaner_wrapper = ExceptionWrapper.new({}, BadlyDefinedError.new)
+
+ assert_equal [], nil_backtrace_wrapper.application_trace
+ assert_equal [], nil_cleaner_wrapper.application_trace
+ end
+
+ test '#framework_trace returns traces outside the application' do
+ exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'"))
+ wrapper = ExceptionWrapper.new(@environment, exception)
+
+ assert_equal caller, wrapper.framework_trace
+ end
+
+ test '#framework_trace cannot be nil' do
+ nil_backtrace_wrapper = ExceptionWrapper.new(@environment, BadlyDefinedError.new)
+ nil_cleaner_wrapper = ExceptionWrapper.new({}, BadlyDefinedError.new)
+
+ assert_equal [], nil_backtrace_wrapper.framework_trace
+ assert_equal [], nil_cleaner_wrapper.framework_trace
+ end
+
+ test '#full_trace returns application and framework traces' do
+ exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'"))
+ wrapper = ExceptionWrapper.new(@environment, exception)
+
+ assert_equal exception.backtrace, wrapper.full_trace
+ end
+
+ test '#full_trace cannot be nil' do
+ nil_backtrace_wrapper = ExceptionWrapper.new(@environment, BadlyDefinedError.new)
+ nil_cleaner_wrapper = ExceptionWrapper.new({}, BadlyDefinedError.new)
+
+ assert_equal [], nil_backtrace_wrapper.full_trace
+ assert_equal [], nil_cleaner_wrapper.full_trace
+ end
+
+ test '#traces returns every trace by category enumerated with an index' do
+ exception = TestError.new("lib/file.rb:42:in `index'", "/gems/rack.rb:43:in `index'")
+ wrapper = ExceptionWrapper.new(@environment, exception)
+
+ assert_equal({
+ 'Application Trace' => [ id: 0, trace: "lib/file.rb:42:in `index'" ],
+ 'Framework Trace' => [ id: 1, trace: "/gems/rack.rb:43:in `index'" ],
+ 'Full Trace' => [
+ { id: 0, trace: "lib/file.rb:42:in `index'" },
+ { id: 1, trace: "/gems/rack.rb:43:in `index'" }
+ ]
+ }, wrapper.traces)
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 7f340ced41..3017a9c2d6 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -3,7 +3,7 @@ require 'abstract_unit'
class MimeTypeTest < ActiveSupport::TestCase
test "parse single" do
- Mime::LOOKUP.keys.each do |mime_type|
+ Mime::LOOKUP.each_key do |mime_type|
unless mime_type == 'image/*'
assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type)
end
@@ -83,7 +83,7 @@ class MimeTypeTest < ActiveSupport::TestCase
test "parse broken acceptlines" do
accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5"
expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL]
- assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
+ assert_equal expect, Mime::Type.parse(accept).collect(&:to_s)
end
# Accept header send with user HTTP_USER_AGENT: Mozilla/4.0
@@ -91,7 +91,7 @@ class MimeTypeTest < ActiveSupport::TestCase
test "parse other broken acceptlines" do
accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*"
expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL]
- assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
+ assert_equal expect, Mime::Type.parse(accept).collect(&:to_s)
end
test "custom type" do
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index c609075e6b..b765a13fa1 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -39,7 +39,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
test "nils are stripped from collections" do
assert_parses(
- {"person" => nil},
+ {"person" => []},
"{\"person\":[null]}", { 'CONTENT_TYPE' => 'application/json' }
)
assert_parses(
@@ -47,7 +47,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
"{\"person\":[\"foo\",null]}", { 'CONTENT_TYPE' => 'application/json' }
)
assert_parses(
- {"person" => nil},
+ {"person" => []},
"{\"person\":[null, null]}", { 'CONTENT_TYPE' => 'application/json' }
)
end
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index 4e99c26e03..50daafbb54 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -95,8 +95,8 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
assert_parses({"action" => nil}, "action")
assert_parses({"action" => {"foo" => nil}}, "action[foo]")
assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]")
- assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar][]")
- assert_parses({"action" => {"foo" => nil }}, "action[foo][]")
+ assert_parses({"action" => {"foo" => { "bar" => [] }}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => [] }}, "action[foo][]")
assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]")
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 00b80c7357..ee8e915610 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -683,6 +683,22 @@ class RequestMethod < BaseRequestTest
end
end
+ test "exception on invalid HTTP method unaffected by I18n settings" do
+ old_locales = I18n.available_locales
+ old_enforce = I18n.config.enforce_available_locales
+
+ begin
+ I18n.available_locales = [:nl]
+ I18n.config.enforce_available_locales = true
+ assert_raise(ActionController::UnknownHttpMethod) do
+ stub_request('REQUEST_METHOD' => '_RANDOM_METHOD').method
+ end
+ ensure
+ I18n.available_locales = old_locales
+ I18n.config.enforce_available_locales = old_enforce
+ end
+ end
+
test "post masquerading as patch" do
request = stub_request(
'REQUEST_METHOD' => 'PATCH',
@@ -915,7 +931,7 @@ class RequestParameters < BaseRequestTest
2.times do
assert_raises(ActionController::BadRequest) do
- # rack will raise a TypeError when parsing this query string
+ # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
request.parameters
end
end
@@ -941,7 +957,7 @@ class RequestParameters < BaseRequestTest
)
assert_raises(ActionController::BadRequest) do
- # rack will raise a TypeError when parsing this query string
+ # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
request.parameters
end
end
@@ -950,7 +966,7 @@ class RequestParameters < BaseRequestTest
request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
e = assert_raises(ActionController::BadRequest) do
- # rack will raise a TypeError when parsing this query string
+ # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
request.parameters
end
@@ -981,8 +997,8 @@ class RequestParameterFilter < BaseRequestTest
}
parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
- before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
- after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
+ before_filter['barg'] = {:bargain=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
+ after_filter['barg'] = {:bargain=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
assert_equal after_filter, parameter_filter.filter(before_filter)
end
@@ -1127,6 +1143,13 @@ class RequestVariant < BaseRequestTest
end
end
+ test "reset variant" do
+ request = stub_request
+
+ request.variant = nil
+ assert_equal nil, request.variant
+ end
+
test "setting variant with non symbol value" do
request = stub_request
assert_raise ArgumentError do
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 187b9a2420..48342e252a 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -1,4 +1,6 @@
require 'abstract_unit'
+require 'timeout'
+require 'rack/content_length'
class ResponseTest < ActiveSupport::TestCase
def setup
@@ -220,9 +222,9 @@ class ResponseTest < ActiveSupport::TestCase
assert @response.respond_to?(:method_missing, true)
end
- test "can be destructured into status, headers and an enumerable body" do
+ test "can be explicitly destructured into status, headers and an enumerable body" do
response = ActionDispatch::Response.new(404, { 'Content-Type' => 'text/plain' }, ['Not Found'])
- status, headers, body = response
+ status, headers, body = *response
assert_equal 404, status
assert_equal({ 'Content-Type' => 'text/plain' }, headers)
@@ -231,12 +233,38 @@ class ResponseTest < ActiveSupport::TestCase
test "[response].flatten does not recurse infinitely" do
Timeout.timeout(1) do # use a timeout to prevent it stalling indefinitely
- status, headers, body = [@response].flatten
+ status, headers, body = assert_deprecated { [@response].flatten }
assert_equal @response.status, status
assert_equal @response.headers, headers
assert_equal @response.body, body.each.to_a.join
end
end
+
+ test "compatibility with Rack::ContentLength" do
+ @response.body = 'Hello'
+ app = lambda { |env| @response.to_a }
+ env = Rack::MockRequest.env_for("/")
+
+ status, headers, body = app.call(env)
+ assert_nil headers['Content-Length']
+
+ status, headers, body = Rack::ContentLength.new(app).call(env)
+ assert_equal '5', headers['Content-Length']
+ end
+
+ test "implicit destructuring and Array conversion is deprecated" do
+ response = ActionDispatch::Response.new(404, { 'Content-Type' => 'text/plain' }, ['Not Found'])
+
+ assert_deprecated do
+ status, headers, body = response
+
+ assert_equal 404, status
+ assert_equal({ 'Content-Type' => 'text/plain' }, headers)
+ assert_equal ['Not Found'], body.each.to_a
+ end
+
+ assert_deprecated { response.to_ary }
+ end
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb
index ff33dd5652..3d3d4b74ae 100644
--- a/actionpack/test/dispatch/routing/inspector_test.rb
+++ b/actionpack/test/dispatch/routing/inspector_test.rb
@@ -2,6 +2,11 @@ require 'abstract_unit'
require 'rails/engine'
require 'action_dispatch/routing/inspector'
+class MountedRackApp
+ def self.call(env)
+ end
+end
+
module ActionDispatch
module Routing
class RoutesInspectorTest < ActiveSupport::TestCase
@@ -204,19 +209,36 @@ module ActionDispatch
], output
end
- class RackApp
- def self.call(env)
+ def test_rake_routes_shows_route_with_rack_app
+ output = draw do
+ get 'foo/:id' => MountedRackApp, :id => /[A-Z]\d{5}/
end
+
+ assert_equal [
+ "Prefix Verb URI Pattern Controller#Action",
+ " GET /foo/:id(.:format) MountedRackApp {:id=>/[A-Z]\\d{5}/}"
+ ], output
end
- def test_rake_routes_shows_route_with_rack_app
+ def test_rake_routes_shows_named_route_with_mounted_rack_app
output = draw do
- get 'foo/:id' => RackApp, :id => /[A-Z]\d{5}/
+ mount MountedRackApp => '/foo'
end
assert_equal [
- "Prefix Verb URI Pattern Controller#Action",
- " GET /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"
+ " Prefix Verb URI Pattern Controller#Action",
+ "mounted_rack_app /foo MountedRackApp"
+ ], output
+ end
+
+ def test_rake_routes_shows_overridden_named_route_with_mounted_rack_app_with_name
+ output = draw do
+ mount MountedRackApp => '/foo', as: 'blog'
+ end
+
+ assert_equal [
+ "Prefix Verb URI Pattern Controller#Action",
+ " blog /foo MountedRackApp"
], output
end
@@ -229,21 +251,21 @@ module ActionDispatch
output = draw do
scope :constraint => constraint.new do
- mount RackApp => '/foo'
+ mount MountedRackApp => '/foo'
end
end
assert_equal [
- "Prefix Verb URI Pattern Controller#Action",
- " /foo #{RackApp.name} {:constraint=>( my custom constraint )}"
+ " Prefix Verb URI Pattern Controller#Action",
+ "mounted_rack_app /foo MountedRackApp {:constraint=>( my custom constraint )}"
], output
end
def test_rake_routes_dont_show_app_mounted_in_assets_prefix
output = draw do
- get '/sprockets' => RackApp
+ get '/sprockets' => MountedRackApp
end
- assert_no_match(/RackApp/, output.first)
+ assert_no_match(/MountedRackApp/, output.first)
assert_no_match(/\/sprockets/, output.first)
end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index c465d56bde..8bdb5733dd 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -69,6 +69,86 @@ module ActionDispatch
end
end
+ test "only_path: true with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal '/foo', url_helpers.foo_url(only_path: true)
+ end
+
+ test "only_path: false with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_url and local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false, host: 'example.com')
+ end
+
+ test "only_path: false with *_url and global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+
+ test "only_path: true with *_path" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal '/foo', url_helpers.foo_path(only_path: true)
+ end
+ end
+
+ test "only_path: false with *_path with global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_path with local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false, host: 'example.com')
+ end
+ end
+
+ test "only_path: false with *_path with no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+ end
+
test "explicit keys win over implicit keys" do
draw do
resources :foo do
@@ -80,6 +160,38 @@ module ActionDispatch
assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(2, foo_id: 1)
end
+ test "having an optional scope with resources" do
+ draw do
+ scope "(/:foo)" do
+ resources :users
+ end
+ end
+
+ assert_equal '/users/1', url_helpers.user_path(1)
+ assert_equal '/users/1', url_helpers.user_path(1, foo: nil)
+ assert_equal '/a/users/1', url_helpers.user_path(1, foo: 'a')
+ end
+
+ test "stringified controller and action keys are properly symbolized" do
+ draw do
+ root 'foo#bar'
+ end
+
+ assert_deprecated do
+ assert_equal '/', url_helpers.root_path('controller' => 'foo', 'action' => 'bar')
+ end
+ end
+
+ test "mix of string and symbol keys are properly symbolized" do
+ draw do
+ root 'foo#bar'
+ end
+
+ assert_deprecated do
+ assert_equal '/', url_helpers.root_path('controller' => 'foo', :action => 'bar')
+ end
+ end
+
private
def draw(&block)
@set.draw(&block)
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index d141210ad9..aae95fb355 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -4420,7 +4420,7 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
include Routes.url_helpers
- test "url helpers raise a helpful error message whem generation fails" do
+ test "url helpers raise a helpful error message when generation fails" do
url, missing = { action: 'show', controller: 'products', id: nil }, [:id]
message = "No route matches #{url.inspect} missing required keys: #{missing.inspect}"
@@ -4433,3 +4433,31 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
assert_equal message, error.message
end
end
+
+class TestDefaultUrlOptions < ActionDispatch::IntegrationTest
+ class PostsController < ActionController::Base
+ def archive
+ render :text => "posts#archive"
+ end
+ end
+
+ Routes = ActionDispatch::Routing::RouteSet.new
+ Routes.draw do
+ default_url_options locale: 'en'
+ scope ':locale', format: false do
+ get '/posts/:year/:month/:day', to: 'posts#archive', as: 'archived_posts'
+ end
+ end
+
+ APP = build_app Routes
+
+ def app
+ APP
+ end
+
+ include Routes.url_helpers
+
+ def test_positional_args_with_format_false
+ assert_equal '/en/posts/2014/12/13', archived_posts_path(2014, 12, 13)
+ end
+end
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index 6f7373201c..7f1207eaed 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -200,7 +200,8 @@ class StaticTest < ActiveSupport::TestCase
}
def setup
- @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/public", "public, max-age=60")
+ @root = "#{FIXTURE_LOAD_PATH}/public"
+ @app = ActionDispatch::Static.new(DummyApp, @root, "public, max-age=60")
end
def public_path
@@ -208,11 +209,28 @@ class StaticTest < ActiveSupport::TestCase
end
include StaticTests
+
+ def test_custom_handler_called_when_file_is_outside_root
+ filename = 'shared.html.erb'
+ assert File.exist?(File.join(@root, '..', filename))
+ env = {
+ "REQUEST_METHOD"=>"GET",
+ "REQUEST_PATH"=>"/..%2F#{filename}",
+ "PATH_INFO"=>"/..%2F#{filename}",
+ "REQUEST_URI"=>"/..%2F#{filename}",
+ "HTTP_VERSION"=>"HTTP/1.1",
+ "SERVER_NAME"=>"localhost",
+ "SERVER_PORT"=>"8080",
+ "QUERY_STRING"=>""
+ }
+ assert_equal(DummyApp.call(nil), @app.call(env))
+ end
end
class StaticEncodingTest < StaticTest
def setup
- @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/公共", "public, max-age=60")
+ @root = "#{FIXTURE_LOAD_PATH}/公共"
+ @app = ActionDispatch::Static.new(DummyApp, @root, "public, max-age=60")
end
def public_path
diff --git a/actionpack/test/dispatch/template_assertions_test.rb b/actionpack/test/dispatch/template_assertions_test.rb
index 3c393f937b..7278754b49 100644
--- a/actionpack/test/dispatch/template_assertions_test.rb
+++ b/actionpack/test/dispatch/template_assertions_test.rb
@@ -10,7 +10,7 @@ class AssertTemplateController < ActionController::Base
end
def render_with_layout
- @variable_for_layout = nil
+ @variable_for_layout = 'hello'
render 'test/hello_world', layout: "layouts/standard"
end
@@ -95,4 +95,16 @@ class AssertTemplateControllerTest < ActionDispatch::IntegrationTest
session.assert_template file: nil
end
end
+
+ def test_assigns_do_not_reset_template_assertion
+ get '/assert_template/render_with_layout'
+ assert_equal 'hello', assigns(:variable_for_layout)
+ assert_template layout: 'layouts/standard'
+ end
+
+ def test_cookies_do_not_reset_template_assertion
+ get '/assert_template/render_with_layout'
+ cookies
+ assert_template layout: 'layouts/standard'
+ end
end
diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb
index 65ad8677f3..cc35d4594e 100644
--- a/actionpack/test/dispatch/test_request_test.rb
+++ b/actionpack/test/dispatch/test_request_test.rb
@@ -18,7 +18,7 @@ class TestRequestTest < ActiveSupport::TestCase
assert_equal "0.0.0.0", env.delete("REMOTE_ADDR")
assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT")
- assert_equal [1, 2], env.delete("rack.version")
+ assert_equal [1, 3], env.delete("rack.version")
assert_equal "", env.delete("rack.input").string
assert_kind_of StringIO, env.delete("rack.errors")
assert_equal true, env.delete("rack.multithread")
diff --git a/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
new file mode 100644
index 0000000000..7d2326e04d
--- /dev/null
+++ b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
@@ -0,0 +1,5 @@
+module Admin
+ module UsersHelpeR
+ end
+end
+
diff --git a/actionpack/test/fixtures/localized/hello_world.de.html b/actionpack/test/fixtures/localized/hello_world.de.html
index 4727d7a7e0..a8fc612c60 100644
--- a/actionpack/test/fixtures/localized/hello_world.de.html
+++ b/actionpack/test/fixtures/localized/hello_world.de.html
@@ -1 +1 @@
-Gutten Tag \ No newline at end of file
+Guten Tag \ No newline at end of file
diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb
index 9dfdfc23ed..6939b426f6 100644
--- a/actionpack/test/journey/path/pattern_test.rb
+++ b/actionpack/test/journey/path/pattern_test.rb
@@ -16,6 +16,7 @@ module ActionDispatch
'/:controller(.:format)' => %r{\A/(#{x})(?:\.([^/.?]+))?\Z},
'/:controller/*foo' => %r{\A/(#{x})/(.+)\Z},
'/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar\Z},
+ '/:foo|*bar' => %r{\A/(?:([^/.?]+)|(.+))\Z},
}.each do |path, expected|
define_method(:"test_to_regexp_#{path}") do
strexp = Router::Strexp.build(
@@ -39,6 +40,7 @@ module ActionDispatch
'/:controller(.:format)' => %r{\A/(#{x})(?:\.([^/.?]+))?},
'/:controller/*foo' => %r{\A/(#{x})/(.+)},
'/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar},
+ '/:foo|*bar' => %r{\A/(?:([^/.?]+)|(.+))},
}.each do |path, expected|
define_method(:"test_to_non_anchored_regexp_#{path}") do
strexp = Router::Strexp.build(
diff --git a/actionpack/test/journey/route/definition/scanner_test.rb b/actionpack/test/journey/route/definition/scanner_test.rb
index 624e6df51a..7a510f1e07 100644
--- a/actionpack/test/journey/route/definition/scanner_test.rb
+++ b/actionpack/test/journey/route/definition/scanner_test.rb
@@ -11,12 +11,25 @@ module ActionDispatch
# /page/:id(/:action)(.:format)
def test_tokens
[
- ['/', [[:SLASH, '/']]],
- ['*omg', [[:STAR, '*omg']]],
- ['/page', [[:SLASH, '/'], [:LITERAL, 'page']]],
- ['/~page', [[:SLASH, '/'], [:LITERAL, '~page']]],
- ['/pa-ge', [[:SLASH, '/'], [:LITERAL, 'pa-ge']]],
- ['/:page', [[:SLASH, '/'], [:SYMBOL, ':page']]],
+ ['/', [[:SLASH, '/']]],
+ ['*omg', [[:STAR, '*omg']]],
+ ['/page', [[:SLASH, '/'], [:LITERAL, 'page']]],
+ ['/page!', [[:SLASH, '/'], [:LITERAL, 'page!']]],
+ ['/page$', [[:SLASH, '/'], [:LITERAL, 'page$']]],
+ ['/page&', [[:SLASH, '/'], [:LITERAL, 'page&']]],
+ ["/page'", [[:SLASH, '/'], [:LITERAL, "page'"]]],
+ ['/page*', [[:SLASH, '/'], [:LITERAL, 'page*']]],
+ ['/page+', [[:SLASH, '/'], [:LITERAL, 'page+']]],
+ ['/page,', [[:SLASH, '/'], [:LITERAL, 'page,']]],
+ ['/page;', [[:SLASH, '/'], [:LITERAL, 'page;']]],
+ ['/page=', [[:SLASH, '/'], [:LITERAL, 'page=']]],
+ ['/page@', [[:SLASH, '/'], [:LITERAL, 'page@']]],
+ ['/page\:', [[:SLASH, '/'], [:LITERAL, 'page:']]],
+ ['/page\(', [[:SLASH, '/'], [:LITERAL, 'page(']]],
+ ['/page\)', [[:SLASH, '/'], [:LITERAL, 'page)']]],
+ ['/~page', [[:SLASH, '/'], [:LITERAL, '~page']]],
+ ['/pa-ge', [[:SLASH, '/'], [:LITERAL, 'pa-ge']]],
+ ['/:page', [[:SLASH, '/'], [:SYMBOL, ':page']]],
['/(:page)', [
[:SLASH, '/'],
[:LPAREN, '('],
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index 8e90d4100f..19c61b5914 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -201,6 +201,16 @@ module ActionDispatch
assert_match(/missing required keys: \[:id\]/, error.message)
end
+ def test_does_not_include_missing_keys_message
+ route_name = "gorby_thunderhorse"
+
+ error = assert_raises(ActionController::UrlGenerationError) do
+ @formatter.generate(route_name, { }, { })
+ end
+
+ assert_no_match(/missing required keys: \[\]/, error.message)
+ end
+
def test_X_Cascade
add_routes @router, [ "/messages(.:format)" ]
resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }))
@@ -405,7 +415,7 @@ module ActionDispatch
def test_generate_with_name
path = Path::Pattern.from_string '/:controller(/:action)'
- @router.routes.add_route @app, path, {}, {}, {}
+ @router.routes.add_route @app, path, {}, {}, "tasks"
path, params = @formatter.generate(
"tasks",
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index b8b51d86c2..ce9522d12a 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -28,30 +28,6 @@ class Customer < Struct.new(:name, :id)
end
end
-class ValidatedCustomer < Customer
- def errors
- if name =~ /Sikachu/i
- []
- else
- [{:name => "is invalid"}]
- end
- end
-end
-
-module Quiz
- class Question < Struct.new(:name, :id)
- extend ActiveModel::Naming
- include ActiveModel::Conversion
-
- def persisted?
- id.present?
- end
- end
-
- class Store < Question
- end
-end
-
class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost)
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -95,24 +71,3 @@ class Comment
attr_accessor :body
end
-
-module Blog
- def self.use_relative_model_naming?
- true
- end
-
- class Post < Struct.new(:title, :id)
- extend ActiveModel::Naming
- include ActiveModel::Conversion
-
- def persisted?
- id.present?
- end
- end
-end
-
-class RenderJsonTestException < Exception
- def as_json(options = nil)
- { :error => self.class.name, :message => self.to_s }
- end
-end