diff options
Diffstat (limited to 'actionpack')
89 files changed, 830 insertions, 955 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 158b22c0cc..6c4ce6195e 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,396 +1,94 @@ -* Deprecate the `only_path` option on `*_path` helpers. +* Remove `respond_to`/`respond_with` placeholder methods, this functionality + has been extracted to the `responders` gem. - In cases where this option is set to `true`, the option is redundant and can - be safely removed; otherwise, the corresponding `*_url` helper should be - used instead. + *Carlos Antonio da Silva* - Fixes #17294. +* Remove deprecated assertion files. - *Dan Olson*, *Godfrey Chan* - -* Improve Journey compliance to RFC 3986. - - The scanner in Journey failed to recognize routes that use literals - from the sub-delims section of RFC 3986. It's now able to parse those - authorized delimiters and route as expected. - - Fixes #17212. - - *Nicolas Cavigneaux* - -* Deprecate implicit Array conversion for Response objects. It was added - (using `#to_ary`) so we could conveniently use implicit splatting: - - status, headers, body = response - - But it also means `response + response` works and `[response].flatten` - cascades down to the Rack body. Nonsense behavior. Instead, rely on - explicit conversion and splatting with `#to_a`: - - status, header, body = *response - - *Jeremy Kemper* - -* Don't rescue `IPAddr::InvalidAddressError`. - - `IPAddr::InvalidAddressError` does not exist in Ruby 1.9.3 - and fails for JRuby in 1.9 mode. - - *Peter Suschlik* - -* Fix bug where the router would ignore any constraints added to redirect - routes. - - Fixes #16605. - - *Agis Anastasopoulos* - -* Allow `config.action_dispatch.trusted_proxies` to accept an IPAddr object. - - Example: - - # config/environments/production.rb - config.action_dispatch.trusted_proxies = IPAddr.new('4.8.15.0/16') - - *Sam Aarons* - -* Avoid duplicating routes for HEAD requests. - - 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. - - *Guo Xiang Tan*, *Andrew White* - -* 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. - - *Richard Schneeman* - -* `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* + *Rafael Mendonça França* -* 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. +* Remove deprecated usage of string keys in URL helpers. - *Xavier Defrang* + *Rafael Mendonça França* -* Properly treat the entire IPv6 User Local Address space as private for - purposes of remote IP detection. Also handle uppercase private IPv6 - addresses. +* Remove deprecated `only_path` option on `*_path` helpers. - Fixes #12638. + *Rafael Mendonça França* - *Caleb Spare* +* Remove deprecated `NamedRouteCollection#helpers`. -* Fixed an issue with migrating legacy json cookies. + *Rafael Mendonça França* - 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. +* Remove deprecated support to define routes with `:to` option that doesn't contain `#`. - 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. + *Rafael Mendonça França* - Fixes #14774. +* Remove deprecated `ActionDispatch::Response#to_ary`. - *Godfrey Chan* + *Rafael Mendonça França* -* Make URL escaping more consistent: +* Remove deprecated `ActionDispatch::Request#deep_munge`. - 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 + *Rafael Mendonça França* - 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. +* Remove deprecated `ActionDispatch::Http::Parameters#symbolized_path_parameters`. - Fixes #14629, #14636 and #14070. + *Rafael Mendonça França* - *Andrew White*, *Edho Arief* +* Remove deprecated option `use_route` in controller tests. -* Add alias `ActionDispatch::Http::UploadedFile#to_io` to - `ActionDispatch::Http::UploadedFile#tempfile`. + *Rafael Mendonça França* - *Tim Linquist* +* Ensure `append_info_to_payload` is called even if an exception is raised. -* Returns null type format when format is not know and controller is using `any` - format block. + Fixes an issue where when an exception is raised in the request the additonal + payload data is not available. - Fixes #14462. + See: + * #14903 + * https://github.com/roidrage/lograge/issues/37 - *Rafael Mendonça França* + *Dieter Komendera*, *Margus Pärt* -* Improve routing error page with fuzzy matching search. +* Correctly rely on the response's status code to handle calls to `head`. - *Winston* + *Robin Dupret* -* Only make deeply nested routes shallow when parent is shallow. +* Using `head` method returns empty response_body instead + of returning a single space " ". - Fixes #14684. + 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. - *Andrew White*, *James Coglan* + Fixes #18253. -* Append link to bad code to backtrace when exception is `SyntaxError`. + *Prathamesh Sonpatki* - *Boris Kuznetsov* +* Fix how polymorphic routes works with objects that implement `to_model`. -* Swapped the parameters of assert_equal in `assert_select` so that the - proper values were printed correctly. + *Travis Grathwell* - Fixes #14422. +* Stop converting empty arrays in `params` to `nil` - *Vishal Lal* + This behaviour was introduced in response to CVE-2012-2660, CVE-2012-2694 + and CVE-2013-0155 -* 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. + 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). - Fixes #14388. + *Chris Sinjakli* - *Andrew White* +* Fixed usage of optional scopes in url helpers. -* Make logging of CSRF failures optional (but on by default) with the - `log_warning_on_csrf_failure` configuration setting in - `ActionController::RequestForgeryProtection`. + *Alex Robbin* - *John Barton* +* Fixed handling of positional url helper arguments when `format: false`. -* Fix URL generation in controller tests with request-dependent - `default_url_options` methods. + Fixes #17819. - *Tony Wooster* + *Andrew White*, *Tatiana Soukiassian* -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/MIT-LICENSE b/actionpack/MIT-LICENSE index d58dd9ed9b..3ec7a617cf 100644 --- a/actionpack/MIT-LICENSE +++ b/actionpack/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2014 David Heinemeier Hansson +Copyright (c) 2004-2015 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 5196e67e55..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', '>= 1.0.1' - s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.4' + 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..8c7cec3561 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -12,7 +12,7 @@ module AbstractController class ActionNotFound < StandardError end - # <tt>AbstractController::Base</tt> is a low-level API. Nobody should be + # AbstractController::Base is a low-level API. Nobody should be # using it directly, and subclasses (like ActionController::Base) are # expected to provide their own +render+ method, since rendering means # different things depending on the context. @@ -69,9 +69,9 @@ module AbstractController # A list of method names that should be considered actions. This # includes all public instance methods on a controller, less - # any internal methods (see #internal_methods), adding back in + # any internal methods (see internal_methods), adding back in # any methods that are internal, but still exist on the class - # itself. Finally, #hidden_actions are removed. + # itself. Finally, hidden_actions are removed. # # ==== Returns # * <tt>Set</tt> - A set of all methods that should be considered actions. @@ -82,25 +82,28 @@ 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 - # Clear out AS callback method pollution - Set.new(methods.reject { |method| method =~ /_one_time_conditions/ }) + methods.to_set end end # action_methods are cached and there is sometimes need to refresh - # them. clear_action_methods! allows you to do that, so next time + # them. ::clear_action_methods! allows you to do that, so next time # you run action_methods, they will be recalculated def clear_action_methods! @action_methods = nil end # Returns the full controller name, underscored, without the ending Controller. - # For instance, MyApp::MyPostsController would return "my_app/my_posts" for - # controller_path. + # + # class MyApp::MyPostsController < AbstractController::Base + # end + # end + # + # MyApp::MyPostsController.controller_path # => "my_app/my_posts" # # ==== Returns # * <tt>String</tt> @@ -137,12 +140,12 @@ module AbstractController process_action(action_name, *args) end - # Delegates to the class' #controller_path + # Delegates to the class' ::controller_path def controller_path self.class.controller_path end - # Delegates to the class' #action_methods + # Delegates to the class' ::action_methods def action_methods self.class.action_methods end diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index ca5c80cd71..32de82780f 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -9,7 +9,7 @@ module AbstractController included do define_callbacks :process_action, - terminator: ->(controller,_) { controller.response_body }, + terminator: ->(controller, result_lambda) { result_lambda.call if result_lambda.is_a?(Proc); controller.response_body }, skip_after_callbacks_if_terminated: true end @@ -22,10 +22,11 @@ module AbstractController end module ClassMethods - # If :only or :except are used, convert the options into the - # :unless and :if options of ActiveSupport::Callbacks. - # The basic idea is that :only => :index gets converted to - # :if => proc {|c| c.action_name == "index" }. + # If +:only+ or +:except+ are used, convert the options into the + # +:if+ and +:unless+ options of ActiveSupport::Callbacks. + # + # The basic idea is that <tt>:only => :index</tt> gets converted to + # <tt>:if => proc {|c| c.action_name == "index" }</tt>. # # ==== Options # * <tt>only</tt> - The callback should be run only for this action diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index df7382f02d..109eff10eb 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -184,7 +184,7 @@ module AbstractController module_name = name.sub(/Controller$/, '') module_path = module_name.underscore helper module_path - rescue MissingSourceFile => e + rescue LoadError => e raise e unless e.is_missing? "helpers/#{module_path}_helper" rescue NameError => e raise e unless e.missing_name? "#{module_name}Helper" diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 9d10140ed2..5514213ad8 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -17,8 +17,8 @@ module AbstractController extend ActiveSupport::Concern include ActionView::ViewPaths - # Normalize arguments, options and then delegates render_to_body and - # sticks the result in self.response_body. + # Normalizes arguments, options and then delegates render_to_body and + # sticks the result in <tt>self.response_body</tt>. # :api: public def render(*args, &block) options = _normalize_render(*args, &block) @@ -30,11 +30,11 @@ module AbstractController # Raw rendering of a template to a string. # # It is similar to render, except that it does not - # set the response_body and it should be guaranteed + # set the +response_body+ and it should be guaranteed # to always return a string. # - # If a component extends the semantics of response_body - # (as Action Controller extends it to be anything that + # If a component extends the semantics of +response_body+ + # (as ActionController extends it to be anything that # responds to the method each), this method needs to be # overridden in order to still return a string. # :api: plugin @@ -73,8 +73,9 @@ module AbstractController } end - # Normalize args by converting render "foo" to render :action => "foo" and - # render "foo/bar" to render :file => "foo/bar". + # Normalize args by converting <tt>render "foo"</tt> to + # <tt>render :action => "foo"</tt> and <tt>render "foo/bar"</tt> to + # <tt>render :file => "foo/bar"</tt>. # :api: plugin def _normalize_args(action=nil, options={}) if action.is_a? Hash 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 6dd213b2f7..993f8e150d 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -173,6 +173,7 @@ module ActionController def status @_status end + alias :response_code :status # :nodoc: def status=(status) @_status = Rack::Utils.status_code(status) @@ -236,9 +237,5 @@ module ActionController lambda { |env| new.dispatch(name, klass.new(env)) } end end - - def _status_code #:nodoc: - @_status - end end end 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/head.rb b/actionpack/lib/action_controller/metal/head.rb index 3d2badf9c2..0d93e2f7aa 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 - if include_content?(self._status_code) + self.response_body = "" + + if include_content?(self.response_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..a3e1a71b0a 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -21,17 +21,20 @@ 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") } ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup) ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload| - result = super - payload[:status] = response.status - append_info_to_payload(payload) - result + begin + result = super + payload[:status] = response.status + result + ensure + append_info_to_payload(payload) + end end end diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index 1e13b3761f..7590fb6843 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -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 ac1f209232..7dae171215 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,28 +1,7 @@ -require 'active_support/core_ext/array/extract_options' require 'abstract_controller/collector' module ActionController #:nodoc: module MimeResponds - extend ActiveSupport::Concern - - module ClassMethods - def respond_to(*) - raise NoMethodError, "The controller-level `respond_to' feature has " \ - "been extracted to the `responders` gem. Add it to your Gemfile to " \ - "continue using this feature:\n" \ - " gem 'responders', '~> 2.0'\n" \ - "Consult the Rails upgrade guide for details." - end - end - - def respond_with(*) - raise NoMethodError, "The `respond_with' feature has been extracted " \ - "to the `responders` gem. Add it to your Gemfile to continue using " \ - "this feature:\n" \ - " gem 'responders', '~> 2.0'\n" \ - "Consult the Rails upgrade guide for details." - end - # Without web-service support, an action which collects the data for displaying a list of people # might look something like this: # diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 09c7a6f946..a7e734db42 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -1,7 +1,6 @@ require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/struct' require 'action_dispatch/http/mime_type' module ActionController @@ -86,7 +85,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 diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index fd20682f8f..0932f03916 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -29,14 +29,7 @@ module ActionController #:nodoc: # you're building an API you'll need something like: # # class ApplicationController < ActionController::Base - # protect_from_forgery - # skip_before_action :verify_authenticity_token, if: :json_request? - # - # protected - # - # def json_request? - # request.format.json? - # end + # protect_from_forgery unless: -> { request.format.json? } # end # # CSRF protection is turned on with the <tt>protect_from_forgery</tt> method, @@ -93,6 +86,7 @@ module ActionController #:nodoc: # Valid Options: # # * <tt>:only/:except</tt> - Passed to the <tt>before_action</tt> call. Set which actions are verified. + # * <tt>:if/:unless</tt> - Passed to the <tt>before_action</tt> call. Set when actions are verified. # * <tt>:with</tt> - Set the method to handle unverified request. # # Valid unverified request handling methods are: @@ -209,6 +203,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 " \ diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index a5ee1e2159..01bbd749c1 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -92,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>. # @@ -163,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 30eae41f60..d30615fade 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -66,7 +66,10 @@ module ActionController def reset_template_assertion RENDER_TEMPLATE_INSTANCE_VARIABLES.each do |instance_variable| - instance_variable_get("@_#{instance_variable}").clear + ivar_name = "@_#{instance_variable}" + if instance_variable_defined?(ivar_name) + instance_variable_get(ivar_name).clear + end end end @@ -144,6 +147,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,8 +715,7 @@ module ActionController :relative_url_root => nil, :_recall => @request.path_parameters) - route_name = options.delete :use_route - url, query_string = @routes.path_for(options, route_name).split("?", 2) + url, query_string = @routes.path_for(options).split("?", 2) @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root @request.env["PATH_INFO"] = url diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 11b5e6be33..dcd3ee0644 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2014 David Heinemeier Hansson +# Copyright (c) 2004-2015 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the 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 b9d5009683..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! 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 a5cd26a3c1..c2f05ecc86 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -1,6 +1,5 @@ require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/deprecation' module ActionDispatch module Http @@ -25,13 +24,6 @@ module ActionDispatch @env[PARAMETERS_KEY] = parameters end - def symbolized_path_parameters - ActiveSupport::Deprecation.warn( - '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.' - ) - path_parameters - end - # Returns a hash with the \parameters used to form the \path of the request. # Returned hash keys are strings: # diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 2a7bb374a5..cadbfc88cb 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 @@ -325,15 +337,6 @@ module ActionDispatch LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip end - # 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.' - ) - - Utils.deep_munge(hash) - end - protected def parse_query(qs) Utils.deep_munge(super) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 33de2f8b5f..4061ea71a3 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -1,6 +1,4 @@ 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' @@ -284,20 +282,6 @@ module ActionDispatch # :nodoc: end alias prepare! 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 # # assert_equal 'AuthorOfNewPage', r.cookies['author'] 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/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index 1b914f0637..d7ce6042c2 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -109,7 +109,7 @@ module ActionDispatch svg = to_svg javascripts = [states, fsm_js] - # Annoying hack for 1.9 warnings + # Annoying hack warnings fun_routes = fun_routes stylesheets = stylesheets svg = svg 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/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 9037bf0e0a..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. @@ -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 @@ -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 diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index c1562fcc0d..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 @@ -46,7 +76,7 @@ module ActionDispatch source_to_show_id = source_to_show[:id] end - template = ActionView::Base.new([RESCUES_TEMPLATE_PATH], + template = DebugView.new([RESCUES_TEMPLATE_PATH], request: request, exception: wrapper.exception, traces: traces, diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 7a91674c3c..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 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/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/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 cfe2237512..df5ebb6751 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -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 ac03ecb2c8..8b04dfaa45 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -4,11 +4,9 @@ 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' -require 'active_support/deprecation' module ActionDispatch module Routing @@ -244,12 +242,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 @@ -281,22 +277,8 @@ module ActionDispatch end def split_to(to) - case to - when Symbol - 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(<<-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] + if to =~ /#/ + to.split('#') else [] end @@ -391,7 +373,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: @@ -402,7 +384,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: # @@ -457,7 +439,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>. @@ -582,13 +564,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 @@ -620,6 +596,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 0847842fa2..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: # @@ -251,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 @@ -294,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 a641ea3ea9..b4c861d306 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -6,7 +6,6 @@ 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' @@ -87,7 +86,7 @@ module ActionDispatch # named routes. class NamedRouteCollection #:nodoc: include Enumerable - attr_reader :routes, :url_helpers_module + attr_reader :routes, :url_helpers_module, :path_helpers_module def initialize @routes = {} @@ -102,14 +101,6 @@ module ActionDispatch @path_helpers.include?(key) || @url_helpers.include?(key) end - def helpers - 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 - def helper_names @path_helpers.map(&:to_s) + @url_helpers.map(&:to_s) end @@ -138,7 +129,7 @@ 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, LEGACY + 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, UNKNOWN @path_helpers << path_name @@ -170,25 +161,6 @@ module ActionDispatch routes.length end - def path_helpers_module(warn = false) - if warn - mod = @path_helpers_module - helpers = @path_helpers - Module.new do - include mod - - helpers.each do |meth| - define_method(meth) do |*args, &block| - ActiveSupport::Deprecation.warn("The method `#{meth}` cannot be used here as a full URL is required. Use `#{meth.to_s.sub(/_path$/, '_url')}` instead") - super(*args, &block) - end - end - end - else - @path_helpers_module - end - end - class UrlHelper # :nodoc: def self.create(route, options, route_name, url_strategy) if optimize_helper?(route) @@ -280,14 +252,20 @@ 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 @@ -324,34 +302,7 @@ module ActionDispatch # :stopdoc: # strategy for building urls to send to the client 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 @@ -457,7 +408,7 @@ module ActionDispatch RUBY end - def url_helpers(include_path_helpers = true) + def url_helpers(supports_path = true) routes = self Module.new do @@ -484,14 +435,12 @@ 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) - end - include path_helpers - extend path_helpers + include path_helpers + extend path_helpers + end # plus a singleton class method called _routes ... included do @@ -502,6 +451,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 @@ -523,7 +478,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 @@ -585,7 +540,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 @@ -729,7 +684,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/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb deleted file mode 100644 index fb579b52fe..0000000000 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'active_support/deprecation' - -ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::DomAssertions has been extracted to the rails-dom-testing gem.")
\ No newline at end of file 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 deleted file mode 100644 index 7361e6c44b..0000000000 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'active_support/deprecation' - -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 deleted file mode 100644 index da98b1d6ce..0000000000 --- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'active_support/deprecation' - -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 a9a1576fed..f0e2c5becc 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -480,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.rb b/actionpack/lib/action_pack.rb index 77f656d6f1..f664dab620 100644 --- a/actionpack/lib/action_pack.rb +++ b/actionpack/lib/action_pack.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2014 David Heinemeier Hansson +# Copyright (c) 2004-2015 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb index 9b3ea30f69..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 = "beta4" + 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 63c9ab04c9..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) @@ -260,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 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/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 d6219b7626..5535c7ae78 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -850,3 +850,27 @@ class IntegrationWithRoutingTest < ActionDispatch::IntegrationTest end end end + +# to work in contexts like rspec before(:all) +class IntegrationRequestsWithoutSetup < ActionDispatch::IntegrationTest + self._setup_callbacks = [] + self._teardown_callbacks = [] + + class FooController < ActionController::Base + def ok + cookies[:key] = 'ok' + render plain: 'ok' + end + end + + def test_request + with_routing do |routes| + routes.draw { get ':action' => FooController } + get '/ok' + + assert_response 200 + assert_equal 'ok', response.body + assert_equal 'ok', cookies['key'] + 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/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb index 49be7caf38..864c6ee130 100644 --- a/actionpack/test/controller/log_subscriber_test.rb +++ b/actionpack/test/controller/log_subscriber_test.rb @@ -73,6 +73,16 @@ module Another def with_action_not_found raise AbstractController::ActionNotFound end + + def append_info_to_payload(payload) + super + payload[:test_key] = "test_value" + @last_payload = payload + end + + def last_payload + @last_payload + end end end @@ -163,6 +173,16 @@ class ACLogSubscriberTest < ActionController::TestCase assert_match(/\(Views: [\d.]+ms\)/, logs[1]) end + def test_append_info_to_payload_is_called_even_with_exception + begin + get :with_exception + wait + rescue Exception + end + + assert_equal "test_value", @controller.last_payload[:test_key] + end + def test_process_action_with_filter_parameters @request.env["action_dispatch.parameter_filter"] = [:lifo, :amount] diff --git a/actionpack/test/controller/mime/responders_test.rb b/actionpack/test/controller/mime/responders_test.rb deleted file mode 100644 index 032b4c0ab1..0000000000 --- a/actionpack/test/controller/mime/responders_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'abstract_unit' -require 'controller/fake_models' - -class ResponderTest < ActionController::TestCase - def test_class_level_respond_to - e = assert_raises(NoMethodError) do - Class.new(ActionController::Base) do - respond_to :json - end - end - - assert_includes e.message, '`responders` gem' - assert_includes e.message, '~> 2.0' - end - - def test_respond_with - klass = Class.new(ActionController::Base) do - def index - respond_with Customer.new("david", 13) - end - end - - @controller = klass.new - - e = assert_raises(NoMethodError) do - get :index - end - - assert_includes e.message, '`responders` gem' - assert_includes e.message, '~> 2.0' - end -end 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/render_test.rb b/actionpack/test/controller/render_test.rb index b036b6c08e..929b161eb6 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -217,6 +217,15 @@ class TestController < ActionController::Base head :forbidden, :x_custom_header => "something" end + def head_with_no_content + # Fill in the headers with dummy data to make + # sure they get removed during the testing + response.headers["Content-Type"] = "dummy" + response.headers["Content-Length"] = 42 + + head 204 + end + private def set_variable_for_layout @@ -545,6 +554,14 @@ class HeadRenderTest < ActionController::TestCase end end + def test_head_with_no_content + get :head_with_no_content + + assert_equal 204, @response.status + assert_nil @response.headers["Content-Type"] + assert_nil @response.headers["Content-Length"] + end + def test_head_with_string_status get :head_with_string_status, :status => "404 Eat Dirt" assert_equal 404, @response.response_code 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 475af90032..2e1f21c645 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 @@ -520,18 +521,6 @@ 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 - - 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 @@ -753,6 +742,44 @@ 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 +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 c05cde87e4..0ffa2d2a03 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -54,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')) @@ -276,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 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..6223a52a76 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 @@ -984,6 +987,13 @@ class CookiesTest < ActionController::TestCase assert_cookie_header "user_name=rizwanreza; domain=.nextangle.local; path=/" end + def test_cookie_with_all_domain_option_using_a_non_standard_2_letter_tld + @request.host = "admin.lvh.me" + get :set_cookie_with_domain_and_tld + assert_response :success + assert_cookie_header "user_name=rizwanreza; domain=.lvh.me; path=/" + end + def test_cookie_with_all_domain_option_using_host_with_port_and_tld_length @request.host = "nextangle.local:3000" get :set_cookie_with_domain_and_tld @@ -1155,5 +1165,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 f8851f0152..1e5ed60b09 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -43,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" @@ -120,6 +122,15 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_no_match '<|>', 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 @@ -230,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 @@ -275,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 diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index ad6335f132..3017a9c2d6 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -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 940ebc0224..ee8e915610 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -997,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 @@ -1143,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 48342e252a..c61423dce4 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -231,9 +231,9 @@ class ResponseTest < ActiveSupport::TestCase assert_equal ['Not Found'], body.each.to_a end - test "[response].flatten does not recurse infinitely" do + test "[response.to_a].flatten does not recurse infinitely" do Timeout.timeout(1) do # use a timeout to prevent it stalling indefinitely - status, headers, body = assert_deprecated { [@response].flatten } + status, headers, body = [@response.to_a].flatten assert_equal @response.status, status assert_equal @response.headers, headers assert_equal @response.body, body.each.to_a.join @@ -251,20 +251,6 @@ class ResponseTest < ActiveSupport::TestCase 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 a7acc0de41..fe52c50336 100644 --- a/actionpack/test/dispatch/routing/route_set_test.rb +++ b/actionpack/test/dispatch/routing/route_set_test.rb @@ -105,50 +105,6 @@ module ActionDispatch 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 @@ -160,6 +116,18 @@ 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 + private def draw(&block) @set.draw(&block) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index d0a624784a..450681c356 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -3331,30 +3331,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'comments#index', @response.body end - def test_mix_symbol_to_controller_action - assert_deprecated do - draw do - get '/projects', controller: 'project_files', - action: 'index', - to: :show - end - end - get '/projects' - assert_equal 'project_files#show', @response.body - end - - def test_mix_string_to_controller_action_no_hash - assert_deprecated do - draw do - get '/projects', controller: 'project_files', - action: 'index', - to: 'show' - end - end - get '/projects' - assert_equal 'show#index', @response.body - end - def test_shallow_path_and_prefix_are_not_added_to_non_shallow_routes draw do scope shallow_path: 'projects', shallow_prefix: 'project' do @@ -3629,15 +3605,13 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest assert_match(/Missing :controller/, ex.message) end - def test_missing_action + def test_missing_controller_with_to ex = assert_raises(ArgumentError) { - assert_deprecated do - draw do - get '/foo/bar', :to => 'foo' - end + draw do + get '/foo/bar', :to => 'foo' end } - assert_match(/Missing :action/, ex.message) + assert_match(/Missing :controller/, ex.message) end def test_missing_action_on_hash @@ -4433,3 +4407,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/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/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/router_test.rb b/actionpack/test/journey/router_test.rb index fbac86e8ca..19c61b5914 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -415,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/routing/helper_test.rb b/actionpack/test/routing/helper_test.rb index 09ca7ff73b..0028aaa629 100644 --- a/actionpack/test/routing/helper_test.rb +++ b/actionpack/test/routing/helper_test.rb @@ -26,20 +26,6 @@ module ActionDispatch x.new.pond_duck_path Duck.new end end - - def test_path_deprecation - rs = ::ActionDispatch::Routing::RouteSet.new - rs.draw do - resources :ducks - end - - x = Class.new { - include rs.url_helpers(false) - } - assert_deprecated do - assert_equal '/ducks', x.new.ducks_path - end - end end end end |