diff options
Diffstat (limited to 'actionpack')
25 files changed, 192 insertions, 136 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 99602f14d9..96dee33f7b 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,9 @@ ## Rails 4.0.0 (unreleased) ## +* Allows `assert_redirected_to` to match against a regular expression. *Andy Lindeman* + +* Add backtrace to development routing error page. *Richard Schneeman* + * Replace `include_seconds` boolean argument with `:include_seconds => true` option in `distance_of_time_in_words` and `time_ago_in_words` signature. *Dmitriy Kiriyenko* diff --git a/actionpack/Rakefile b/actionpack/Rakefile index bb1e704767..17d95bfd1d 100755..100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -1,4 +1,3 @@ -#!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' require 'rubygems/package_task' diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 59ec197347..80901b8bf3 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -133,6 +133,8 @@ module ActionController #:nodoc: end def filter(controller) + cache_layout = @cache_layout.respond_to?(:call) ? @cache_layout.call(controller) : @cache_layout + path_options = if @cache_path.respond_to?(:call) controller.instance_exec(controller, &@cache_path) else @@ -144,13 +146,13 @@ module ActionController #:nodoc: body = controller.read_fragment(cache_path.path, @store_options) unless body - controller.action_has_layout = false unless @cache_layout + controller.action_has_layout = false unless cache_layout yield controller.action_has_layout = true body = controller._save_fragment(cache_path.path, @store_options) end - body = controller.render_to_string(:text => body, :layout => true) unless @cache_layout + body = controller.render_to_string(:text => body, :layout => true) unless cache_layout controller.response_body = body controller.content_type = Mime[cache_path.extension || :html] diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb index 374645c9ce..379ff97048 100644 --- a/actionpack/lib/action_controller/metal/data_streaming.rb +++ b/actionpack/lib/action_controller/metal/data_streaming.rb @@ -14,7 +14,7 @@ module ActionController #:nodoc: protected # Sends the file. This uses a server-appropriate method (such as X-Sendfile) # via the Rack::Sendfile middleware. The header to use is set via - # config.action_dispatch.x_sendfile_header. + # +config.action_dispatch.x_sendfile_header+. # Your server can also configure this for you by setting the X-Sendfile-Type header. # # Be careful to sanitize the path parameter if it is coming from a web diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 17e2db74d4..7e2316d01c 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -48,7 +48,7 @@ module ActionController # method attribute_names. # # If you're going to pass the parameters to an +ActiveModel+ object (such as - # +User.new(params[:user])+), you might consider passing the model class to + # <tt>User.new(params[:user])</tt>), you might consider passing the model class to # the method instead. The +ParamsWrapper+ will actually try to determine the # list of attribute names from the model and only wrap those attributes: # diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb index 040b51e040..a3bb25f75a 100644 --- a/actionpack/lib/action_dispatch/http/headers.rb +++ b/actionpack/lib/action_dispatch/http/headers.rb @@ -14,17 +14,18 @@ module ActionDispatch end def [](header_name) - if include?(header_name) - super - else - super(env_name(header_name)) - end + super env_name(header_name) + end + + def fetch(header_name, default=nil, &block) + super env_name(header_name), default, &block end private - # Converts a HTTP header name to an environment variable name. + # Converts a HTTP header name to an environment variable name if it is + # not contained within the headers hash. def env_name(header_name) - @@env_cache[header_name] + include?(header_name) ? header_name : @@env_cache[header_name] end end end diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 26f4c16218..0eaae80461 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -179,11 +179,11 @@ module Mime end end - # input: 'text' - # returned value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + # For an input of <tt>'text'</tt>, returns <tt>[Mime::JSON, Mime::XML, Mime::ICS, + # Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT]</tt>. # - # input: 'application' - # returned value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM] + # For an input of <tt>'application'</tt>, returns <tt>[Mime::HTML, Mime::JS, + # Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM]</tt>. def parse_data_with_trailing_star(input) Mime::SET.select { |m| m =~ input } end @@ -192,7 +192,7 @@ module Mime # # Usage: # - # Mime::Type.unregister(:mobile) + # Mime::Type.unregister(:mobile) def unregister(symbol) symbol = symbol.to_s.upcase mime = Mime.const_get(symbol) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index d9b63faf5e..bcfd0b0d00 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -35,6 +35,10 @@ module ActionDispatch @env["action_dispatch.request.path_parameters"] ||= {} end + def reset_parameters #:nodoc: + @env.delete("action_dispatch.request.parameters") + end + private # TODO: Validate that the characters are UTF-8. If they aren't, diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 196f655de3..2c0c31de9d 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -227,7 +227,7 @@ module ActionDispatch # cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will # be raised. # - # This jar requires that you set a suitable secret for the verification on your app's config.secret_token. + # This jar requires that you set a suitable secret for the verification on your app's +config.secret_token+. # # Example: # diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb index a0388e0e13..2f6968eb2e 100644 --- a/actionpack/lib/action_dispatch/middleware/reloader.rb +++ b/actionpack/lib/action_dispatch/middleware/reloader.rb @@ -18,10 +18,10 @@ module ActionDispatch # classes before they are unloaded. # # By default, ActionDispatch::Reloader is included in the middleware stack - # only in the development environment; specifically, when config.cache_classes + # only in the development environment; specifically, when +config.cache_classes+ # is false. Callbacks may be registered even when it is not included in the - # middleware stack, but are executed only when +ActionDispatch::Reloader.prepare!+ - # or +ActionDispatch::Reloader.cleanup!+ are called manually. + # middleware stack, but are executed only when <tt>ActionDispatch::Reloader.prepare!</tt> + # or <tt>ActionDispatch::Reloader.cleanup!</tt> are called manually. # class Reloader include ActiveSupport::Callbacks diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 45a00b5056..e82132b445 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -7,6 +7,15 @@ require 'active_support/core_ext/object/blank' module ActionDispatch module Session class SessionRestoreError < StandardError #:nodoc: + attr_reader :original_exception + + def initialize(const_error) + @original_exception = const_error + + super("Session contains objects whose class definition isn't available.\n" + + "Remember to require the classes for all objects kept in the session.\n" + + "(Original exception: #{const_error.message} [#{const_error.class}])\n") + end end module DestroyableSession @@ -58,11 +67,8 @@ module ActionDispatch begin # Note that the regexp does not allow $1 to end with a ':' $1.constantize - rescue LoadError, NameError => const_error - raise ActionDispatch::Session::SessionRestoreError, - "Session contains objects whose class definition isn't available.\n" + - "Remember to require the classes for all objects kept in the session.\n" + - "(Original exception: #{const_error.message} [#{const_error.class}])\n" + rescue LoadError, NameError => e + raise ActionDispatch::Session::SessionRestoreError, e, e.backtrace end retry else diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb index f06c07daa5..177d383e94 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb @@ -12,4 +12,6 @@ <% end %> <p> Try running <code>rake routes</code> for more information on available routes. -</p>
\ No newline at end of file +</p> + +<%= render :template => "rescues/_trace" %> diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 1a1a054985..4ea3937057 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -35,6 +35,8 @@ module ActionDispatch } return true + ensure + req.reset_parameters end def call(env) diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 013cf93dbc..8fde667108 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -43,16 +43,14 @@ module ActionDispatch # edit_polymorphic_path(@post) # => "/posts/1/edit" # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf" # - # == Using with mounted engines + # == Usage with mounted engines # - # If you use mounted engine, there is a possibility that you will need to use - # polymorphic_url pointing at engine's routes. To do that, just pass proxy used - # to reach engine's routes as a first argument: + # If you are using a mounted engine and you need to use a polymorphic_url + # pointing at the engine's routes, pass in the engine's route proxy as the first + # argument to the method. For example: # - # For example: - # - # polymorphic_url([blog, @post]) # it will call blog.post_path(@post) - # form_for([blog, @post]) # => "/blog/posts/1 + # polymorphic_url([blog, @post]) # calls blog.post_path(@post) + # form_for([blog, @post]) # => "/blog/posts/1" # module PolymorphicRoutes # Constructs a call to a named RESTful route for the given record and returns the diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index 444a79c50d..95c588c00a 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -1,5 +1,6 @@ require 'action_dispatch/http/request' require 'active_support/core_ext/uri' +require 'active_support/core_ext/array/extract_options' require 'rack/utils' module ActionDispatch @@ -99,7 +100,7 @@ module ActionDispatch # match 'accounts/:name' => redirect(SubdomainRedirector.new('api')) # def redirect(*args, &block) - options = args.last.is_a?(Hash) ? args.pop : {} + options = args.extract_options! status = options.delete(:status) || 301 return OptionRedirect.new(status, options) if options.any? diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 7a7810a95c..7abd7bd008 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -99,12 +99,12 @@ module ActionDispatch @module = Module.new do protected - def handle_positional_args(args, options, route) + def handle_positional_args(args, options, segment_keys) inner_options = args.extract_options! result = options.dup if args.any? - keys = route.segment_keys + keys = segment_keys if args.size < keys.size - 1 # take format into account keys -= self.url_options.keys if self.respond_to?(:url_options) keys -= options.keys @@ -161,34 +161,13 @@ module ActionDispatch end end - def hash_access_name(name, only_path) - if only_path - :"hash_for_#{name}_path" - else - :"hash_for_#{name}_url" - end - end - def define_named_route_methods(name, route) [true, false].each do |only_path| hash = route.defaults.merge(:use_route => name, :only_path => only_path) - define_hash_access route, name, hash define_url_helper route, name, hash end end - def define_hash_access(route, name, options) - selector = hash_access_name(name, options[:only_path]) - - @module.module_eval do - redefine_method(selector) do |*args| - self.handle_positional_args(args, options, route) - end - protected selector - end - helpers << selector - end - # Create a url helper allowing ordered parameters to be associated # with corresponding dynamic segments, so you can do: # @@ -204,36 +183,26 @@ module ActionDispatch # def define_url_helper(route, name, options) selector = url_helper_name(name, options[:only_path]) - hash_access_method = hash_access_name(name, options[:only_path]) - - if optimize_helper?(route) - @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - remove_possible_method :#{selector} - def #{selector}(*args) - if args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && optimize_routes_generation? - options = #{options.inspect}.merge!(url_options) - options[:path] = "#{optimized_helper(route)}" - ActionDispatch::Http::URL.url_for(options) - else - url_for(#{hash_access_method}(*args)) - end - end - END_EVAL - else - @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - remove_possible_method :#{selector} - def #{selector}(*args) - url_for(#{hash_access_method}(*args)) + + @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 + remove_possible_method :#{selector} + def #{selector}(*args) + if #{optimize_helper?(route)} && args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && optimize_routes_generation? + options = #{options.inspect}.merge!(url_options) + options[:path] = "#{optimized_helper(route)}" + ActionDispatch::Http::URL.url_for(options) + else + url_for(handle_positional_args(args, #{options.inspect}, #{route.segment_keys.inspect})) end - END_EVAL - end + end + END_EVAL helpers << selector end # Clause check about when we need to generate an optimized helper. def optimize_helper?(route) #:nodoc: - route.ast.grep(Journey::Nodes::Star).empty? && route.requirements.except(:controller, :action).empty? + route.requirements.except(:controller, :action).empty? end # Generates the interpolation to be used in the optimized helper. @@ -245,7 +214,10 @@ module ActionDispatch end route.required_parts.each_with_index do |part, i| - string_route.gsub!(part.inspect, "\#{Journey::Router::Utils.escape_fragment(args[#{i}].to_param)}") + # Replace each route parameter + # e.g. :id for regular parameter or *path for globbing + # with ruby string interpolation code + string_route.gsub!(/(\*|:)#{part}/, "\#{Journey::Router::Utils.escape_fragment(args[#{i}].to_param)}") end string_route diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 40d38c59d6..8f6fff5d32 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -53,15 +53,18 @@ module ActionDispatch # # assert that the redirection was to the url for @customer # assert_redirected_to @customer # + # # asserts that the redirection matches the regular expression + # assert_redirected_to %r(\Ahttp://example.org) + # def assert_redirected_to(options = {}, message=nil) assert_response(:redirect, message) - return true if options == @response.location + return true if options === @response.location redirect_is = normalize_argument_to_redirection(@response.location) redirect_expected = normalize_argument_to_redirection(options) message ||= "Expected response to be a redirect to <#{redirect_expected}> but was a redirect to <#{redirect_is}>" - assert_equal redirect_expected, redirect_is, message + assert_operator redirect_expected, :===, redirect_is, message end private @@ -71,17 +74,21 @@ module ActionDispatch end def normalize_argument_to_redirection(fragment) - case fragment - when %r{^\w[A-Za-z\d+.-]*:.*} - fragment - when String - @request.protocol + @request.host_with_port + fragment - when :back - raise RedirectBackError unless refer = @request.headers["Referer"] - refer - else - @controller.url_for(fragment) - end.delete("\0\r\n") + normalized = case fragment + when Regexp + fragment + when %r{^\w[A-Za-z\d+.-]*:.*} + fragment + when String + @request.protocol + @request.host_with_port + fragment + when :back + raise RedirectBackError unless refer = @request.headers["Referer"] + refer + else + @controller.url_for(fragment) + end + + normalized.respond_to?(:delete) ? normalized.delete("\0\r\n") : normalized end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index 60d4af178a..4bcb8b9718 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -113,7 +113,7 @@ module ActionView # == Caching multiple stylesheets into one # # You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be - # compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching + # compressed by gzip (leading to faster transfers). Caching will only happen if +config.perform_caching+ # is set to true (which is the case by default for the Rails production environment, but not for the development # environment). Examples: # diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 6ed265a516..6bd8e62e0d 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -29,7 +29,8 @@ module ActionView # 89 mins, 30 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours # 23 hrs, 59 mins, 30 secs <-> 41 hrs, 59 mins, 29 secs # => 1 day # 41 hrs, 59 mins, 30 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days - # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month + # 29 days, 23 hrs, 59 mins, 30 secs <-> 44 days, 23 hrs, 59 mins, 29 secs # => about 1 month + # 44 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 2 months # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months # 1 yr <-> 1 yr, 3 months # => about 1 year # 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year @@ -95,13 +96,18 @@ module ActionView else locale.t :x_minutes, :count => 1 end - when 2..44 then locale.t :x_minutes, :count => distance_in_minutes - when 45..89 then locale.t :about_x_hours, :count => 1 - when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round - when 1440..2519 then locale.t :x_days, :count => 1 - when 2520..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round - when 43200..86399 then locale.t :about_x_months, :count => 1 - when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round + when 2...45 then locale.t :x_minutes, :count => distance_in_minutes + when 45...90 then locale.t :about_x_hours, :count => 1 + # 90 mins up to 24 hours + when 90...1440 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round + # 24 hours up to 42 hours + when 1440...2520 then locale.t :x_days, :count => 1 + # 42 hours up to 30 days + when 2520...43200 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round + # 30 days up to 60 days + when 43200...86400 then locale.t :about_x_months, :count => (distance_in_minutes.to_f / 43200.0).round + # 60 days up to 365 days + when 86400...525600 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round else if from_time.acts_like?(:time) && to_time.acts_like?(:time) fyear = from_time.year diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index b121ca9481..f5f397c9c0 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -179,6 +179,9 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase assert_redirected_to 'http://test.host/route_two' end assert_raise(ActiveSupport::TestCase::Assertion) do + assert_redirected_to %r(^http://test.host/route_two) + end + assert_raise(ActiveSupport::TestCase::Assertion) do assert_redirected_to :controller => 'action_pack_assertions', :action => 'nothing', :id => 'two' end assert_raise(ActiveSupport::TestCase::Assertion) do @@ -212,6 +215,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase process :redirect_to_top_level_named_route # assert_redirected_to "http://test.host/action_pack_assertions/foo" would pass because of exact match early return assert_redirected_to "/action_pack_assertions/foo" + assert_redirected_to %r(/action_pack_assertions/foo) end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index e8546cb154..9efe328d62 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -236,6 +236,7 @@ class ActionCachingTestController < CachingController caches_action :with_layout caches_action :with_format_and_http_param, :cache_path => Proc.new { |c| { :key => 'value' } } caches_action :layout_false, :layout => false + caches_action :with_layout_proc_param, :layout => Proc.new { |c| c.params[:layout] } caches_action :record_not_found, :four_oh_four, :simple_runtime_error caches_action :streaming @@ -282,6 +283,7 @@ class ActionCachingTestController < CachingController alias_method :edit, :index alias_method :destroy, :index alias_method :layout_false, :with_layout + alias_method :with_layout_proc_param, :with_layout def expire expire_action :controller => 'action_caching_test', :action => 'index' @@ -403,11 +405,40 @@ class ActionCacheTest < ActionController::TestCase get :layout_false assert_response :success assert_not_equal cached_time, @response.body - body = body_to_string(read_fragment('hostname.com/action_caching_test/layout_false')) assert_equal cached_time, body end + def test_action_cache_with_layout_and_layout_cache_false_via_proc + get :with_layout_proc_param, :layout => false + assert_response :success + cached_time = content_to_cache + assert_not_equal cached_time, @response.body + assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param') + reset! + + get :with_layout_proc_param, :layout => false + assert_response :success + assert_not_equal cached_time, @response.body + body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout_proc_param')) + assert_equal cached_time, body + end + + def test_action_cache_with_layout_and_layout_cache_true_via_proc + get :with_layout_proc_param, :layout => true + assert_response :success + cached_time = content_to_cache + assert_not_equal cached_time, @response.body + assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param') + reset! + + get :with_layout_proc_param, :layout => true + assert_response :success + assert_not_equal cached_time, @response.body + body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout_proc_param')) + assert_equal @response.body, body + end + def test_action_cache_conditional_options @request.env['HTTP_ACCEPT'] = 'application/json' get :index diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 9441b46d47..bcb4e6a766 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -891,23 +891,6 @@ class RouteSetTest < ActiveSupport::TestCase MockController.build(set.url_helpers).new end - def test_named_route_hash_access_method - controller = setup_named_route_test - - assert_equal( - { :controller => 'people', :action => 'show', :id => 5, :use_route => "show", :only_path => false }, - controller.send(:hash_for_show_url, :id => 5)) - - assert_equal( - { :controller => 'people', :action => 'index', :use_route => "index", :only_path => false }, - controller.send(:hash_for_index_url)) - - assert_equal( - { :controller => 'people', :action => 'show', :id => 5, :use_route => "show", :only_path => true }, - controller.send(:hash_for_show_path, :id => 5) - ) - end - def test_named_route_url_method controller = setup_named_route_test @@ -919,7 +902,6 @@ class RouteSetTest < ActiveSupport::TestCase assert_equal "http://test.host/admin/users", controller.send(:users_url) assert_equal '/admin/users', controller.send(:users_path) - assert_equal '/admin/users', url_for(set, controller.send(:hash_for_users_url), { :controller => 'users', :action => 'index' }) end def test_named_route_url_method_with_anchor diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb index ec6ba494dc..bc7cad8db5 100644 --- a/actionpack/test/dispatch/header_test.rb +++ b/actionpack/test/dispatch/header_test.rb @@ -13,4 +13,9 @@ class HeaderTest < ActiveSupport::TestCase assert_equal "text/plain", @headers["CONTENT_TYPE"] assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"] end + + test "fetch" do + assert_equal "text/plain", @headers.fetch("content-type", nil) + assert_equal "not found", @headers.fetch('not-found', 'not found') + end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 4b8d308043..a96d2edcf9 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -2512,3 +2512,22 @@ private %(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>) end end + +class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest + Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| + app.draw do + ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + + get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == 'foo' } + get "/:bar" => ok + end + end + + def app; Routes end + + test "parameters are reset between constraint checks" do + get "/bar" + assert_equal nil, @request.params[:foo] + assert_equal "bar", @request.params[:bar] + end +end diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 928c767084..ff85a675a2 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -21,7 +21,7 @@ class DateHelperTest < ActionView::TestCase def assert_distance_of_time_in_words(from, to=nil) to ||= from - # 0..1 with :include_seconds => true + # 0..1 minute with :include_seconds => true assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => true) assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => true) assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => true) @@ -35,7 +35,7 @@ class DateHelperTest < ActionView::TestCase assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => true) assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => true) - # 0..1 with :include_seconds => false + # 0..1 minute with :include_seconds => false assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => false) assert_equal "less than a minute", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => false) assert_equal "less than a minute", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => false) @@ -48,42 +48,53 @@ class DateHelperTest < ActionView::TestCase assert_equal "1 minute", distance_of_time_in_words(from, to + 59.seconds, :include_seconds => false) assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => false) assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => false) - # First case 0..1 + + # Note that we are including a 30-second boundary around the interval we + # want to test. For instance, "1 minute" is actually 30s to 1m29s. The + # reason for doing this is simple -- in `distance_of_time_to_words`, when we + # take the distance between our two Time objects in seconds and convert it + # to minutes, we round the number. So 29s gets rounded down to 0m, 30s gets + # rounded up to 1m, and 1m29s gets rounded down to 1m. A similar thing + # happens with the other cases. + + # First case 0..1 minute assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds) assert_equal "less than a minute", distance_of_time_in_words(from, to + 29.seconds) assert_equal "1 minute", distance_of_time_in_words(from, to + 30.seconds) assert_equal "1 minute", distance_of_time_in_words(from, to + 1.minutes + 29.seconds) - # 2..44 + # 2 minutes up to 45 minutes assert_equal "2 minutes", distance_of_time_in_words(from, to + 1.minutes + 30.seconds) assert_equal "44 minutes", distance_of_time_in_words(from, to + 44.minutes + 29.seconds) - # 45..89 + # 45 minutes up to 90 minutes assert_equal "about 1 hour", distance_of_time_in_words(from, to + 44.minutes + 30.seconds) assert_equal "about 1 hour", distance_of_time_in_words(from, to + 89.minutes + 29.seconds) - # 90..1439 + # 90 minutes up to 24 hours assert_equal "about 2 hours", distance_of_time_in_words(from, to + 89.minutes + 30.seconds) assert_equal "about 24 hours", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 29.seconds) - # 1440..2519 + # 24 hours up to 42 hours assert_equal "1 day", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 30.seconds) assert_equal "1 day", distance_of_time_in_words(from, to + 41.hours + 59.minutes + 29.seconds) - # 2520..43199 + # 42 hours up to 30 days assert_equal "2 days", distance_of_time_in_words(from, to + 41.hours + 59.minutes + 30.seconds) assert_equal "3 days", distance_of_time_in_words(from, to + 2.days + 12.hours) assert_equal "30 days", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 29.seconds) - # 43200..86399 + # 30 days up to 60 days assert_equal "about 1 month", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 30.seconds) - assert_equal "about 1 month", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 29.seconds) + assert_equal "about 1 month", distance_of_time_in_words(from, to + 44.days + 23.hours + 59.minutes + 29.seconds) + assert_equal "about 2 months", distance_of_time_in_words(from, to + 44.days + 23.hours + 59.minutes + 30.seconds) + assert_equal "about 2 months", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 29.seconds) - # 86400..525599 + # 60 days up to 365 days assert_equal "2 months", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 30.seconds) assert_equal "12 months", distance_of_time_in_words(from, to + 1.years - 31.seconds) - # > 525599 + # >= 365 days assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years - 30.seconds) assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years + 3.months - 1.day) assert_equal "over 1 year", distance_of_time_in_words(from, to + 1.years + 6.months) |