diff options
Diffstat (limited to 'actionpack/lib/action_controller')
8 files changed, 68 insertions, 68 deletions
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index f8e0d9cf6c..35befc05e1 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -185,7 +185,7 @@ module ActionController !request.fresh?(response) end - # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a +private+ + # Sets an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+ # instruction, so that intermediate caches must not cache the response. # # expires_in 20.minutes @@ -195,7 +195,7 @@ module ActionController # This method will overwrite an existing Cache-Control header. # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. # - # The method will also ensure a HTTP Date header for client compatibility. + # The method will also ensure an HTTP Date header for client compatibility. def expires_in(seconds, options = {}) response.cache_control.merge!( :max_age => seconds, @@ -208,7 +208,7 @@ module ActionController response.date = Time.now unless response.date? end - # Sets a HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should + # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should # occur by the browser or intermediate caches (like caching proxy servers). def expires_now response.cache_control.replace(:no_cache => true) @@ -216,18 +216,16 @@ module ActionController # Cache or yield the block. The cache is supposed to never expire. # - # You can use this method when you have a HTTP response that never changes, + # You can use this method when you have an HTTP response that never changes, # and the browser and proxies should cache it indefinitely. # # * +public+: By default, HTTP responses are private, cached only on the # user's web browser. To allow proxies to cache the response, set +true+ to # indicate that they can serve the cached response to all users. - # - # * +version+: the version passed as a key for the cache. - def http_cache_forever(public: false, version: 'v1') + def http_cache_forever(public: false) expires_in 100.years, public: public - yield if stale?(etag: "#{version}-#{request.fullpath}", + yield if stale?(etag: request.fullpath, last_modified: Time.new(2011, 1, 1).utc, public: public) end diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index 6b540d42c7..6192fc0f9c 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -1,33 +1,31 @@ require 'active_support/core_ext/string/strip' module ActionController - # Handles implicit rendering for a controller action when it did not - # explicitly indicate an appropiate response via methods such as +render+, - # +respond_to+, +redirect+ or +head+. + # Handles implicit rendering for a controller action that does not + # explicitly respond with +render+, +respond_to+, +redirect+, or +head+. # - # For API controllers, the implicit render always renders "204 No Content" - # and does not account for any templates. + # For API controllers, the implicit response is always 204 No Content. # - # For other controllers, the following conditions are checked: + # For all other controllers, we use these heuristics to decide whether to + # render a template, raise an error for a missing template, or respond with + # 204 No Content: # - # First, if a template exists for the controller action, it is rendered. - # This template lookup takes into account the action name, locales, format, - # variant, template handlers, etc. (see +render+ for details). + # First, if we DO find a template, it's rendered. Template lookup accounts + # for the action name, locales, format, variant, template handlers, and more + # (see +render+ for details). # - # Second, if other templates exist for the controller action but is not in - # the right format (or variant, etc.), an <tt>ActionController::UnknownFormat</tt> - # is raised. The list of available templates is assumed to be a complete - # enumeration of all the possible formats (or variants, etc.); that is, - # having only HTML and JSON templates indicate that the controller action is - # not meant to handle XML requests. + # Second, if we DON'T find a template but the controller action does have + # templates for other formats, variants, etc., then we trust that you meant + # to provide a template for this response, too, and we raise + # <tt>ActionController::UnknownFormat</tt> with an explanation. # - # Third, if the current request is an "interactive" browser request (the user - # navigated here by entering the URL in the address bar, submiting a form, - # clicking on a link, etc. as opposed to an XHR or non-browser API request), - # <tt>ActionView::UnknownFormat</tt> is raised to display a helpful error - # message. + # Third, if we DON'T find a template AND the request is a page load in a web + # browser (technically, a non-XHR GET request for an HTML response) where + # you reasonably expect to have rendered a template, then we raise + # <tt>ActionView::UnknownFormat</tt> with an explanation. # - # Finally, it falls back to the same "204 No Content" behavior as API controllers. + # Finally, if we DON'T find a template AND the request isn't a browser page + # load, then we implicitly respond with 204 No Content. module ImplicitRender # :stopdoc: @@ -37,39 +35,23 @@ module ActionController if template_exists?(action_name.to_s, _prefixes, variants: request.variant) render(*args) elsif any_templates?(action_name.to_s, _prefixes) - message = "#{self.class.name}\##{action_name} does not know how to respond " \ - "to this request. There are other templates available for this controller " \ - "action but none of them were suitable for this request.\n\n" \ - "This usually happens when the client requested an unsupported format " \ - "(e.g. requesting HTML content from a JSON endpoint or vice versa), but " \ - "it might also be failing due to other constraints, such as locales or" \ - "variants.\n" - - if request.formats.any? - message << "\nRequested format(s): #{request.formats.join(", ")}" - end - - if request.variant.any? - message << "\nRequested variant(s): #{request.variant.join(", ")}" - end + message = "#{self.class.name}\##{action_name} is missing a template " \ + "for this request format and variant.\n" \ + "\nrequest.formats: #{request.formats.map(&:to_s).inspect}" \ + "\nrequest.variant: #{request.variant.inspect}" raise ActionController::UnknownFormat, message elsif interactive_browser_request? - message = "You did not define any templates for #{self.class.name}\##{action_name}. " \ - "This is not necessarily a problem (e.g. you might be building an API endpoint " \ - "that does not require any templates), and the controller would usually respond " \ - "with `head :no_content` for your convenience.\n\n" \ - "However, you appear to have navigated here from an interactive browser request – " \ - "such as by navigating to this URL directly, clicking on a link or submitting a form. " \ - "Rendering a `head :no_content` in this case could have resulted in unexpected UI " \ - "behavior in the browser.\n\n" \ - "If you expected the `head :no_content` response, you do not need to take any " \ - "actions – requests coming from an XHR (AJAX) request or other non-browser clients " \ - "will receive the \"204 No Content\" response as expected.\n\n" \ - "If you did not expect this behavior, you can resolve this error by adding a " \ - "template for this controller action (usually `#{action_name}.html.erb`) or " \ - "otherwise indicate the appropriate response in the action using `render`, " \ - "`redirect_to`, `head`, etc.\n" + message = "#{self.class.name}\##{action_name} is missing a template " \ + "for this request format and variant.\n\n" \ + "request.formats: #{request.formats.map(&:to_s).inspect}\n" \ + "request.variant: #{request.variant.inspect}\n\n" \ + "NOTE! For XHR/Ajax or API requests, this action would normally " \ + "respond with 204 No Content: an empty white screen. Since you're " \ + "loading it in a web browser, we assume that you expected to " \ + "actually render a template, not… nothing, so we're showing an " \ + "error to be extra-clear. If you expect 204 No Content, carry on. " \ + "That's what you'll get from an XHR or API request. Give it a shot." raise ActionController::UnknownFormat, message else @@ -85,9 +67,8 @@ module ActionController end private - def interactive_browser_request? - request.format == Mime[:html] && !request.xhr? + request.get? && request.format == Mime[:html] && !request.xhr? end end end diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index bf74b39ac4..885ea3fefd 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -19,6 +19,7 @@ module ActionController :controller => self.class.name, :action => self.action_name, :params => request.filtered_parameters, + :headers => request.headers, :format => request.format.ref, :method => request.request_method, :path => request.fullpath diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 173a14a1d2..2e89af1a5e 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -198,7 +198,7 @@ module ActionController #:nodoc: _process_format(format) _set_rendered_content_type format response = collector.response - response ? response.call : render({}) + response.call if response else raise ActionController::UnknownFormat end diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index b13ba06962..3c7cc15627 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -84,7 +84,7 @@ module ActionController # redirect_back fallback_location: proc { edit_post_url(@post) } # # All options that can be passed to <tt>redirect_to</tt> are accepted as - # options and the behavior is indetical. + # options and the behavior is identical. def redirect_back(fallback_location:, **args) if referer = request.headers["Referer"] redirect_to referer, **args diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb index 81b9a7b9ed..0621a7368c 100644 --- a/actionpack/lib/action_controller/metal/rescue.rb +++ b/actionpack/lib/action_controller/metal/rescue.rb @@ -7,8 +7,12 @@ module ActionController #:nodoc: include ActiveSupport::Rescuable def rescue_with_handler(exception) - if exception.cause && handler_for_rescue(exception.cause) - exception = exception.cause + if exception.cause + handler_index = index_of_handler_for_rescue(exception) || Float::INFINITY + cause_handler_index = index_of_handler_for_rescue(exception.cause) + if cause_handler_index && cause_handler_index <= handler_index + exception = exception.cause + end end super(exception) end diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index a01110d474..76e3b4d25a 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -430,6 +430,21 @@ module ActionController ) end + if Hash.method_defined?(:dig) + # Extracts the nested parameter from the given +keys+ by calling +dig+ + # at each step. Returns +nil+ if any intermediate step is +nil+. + # + # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } }) + # params.dig(:foo, :bar, :baz) # => 1 + # params.dig(:foo, :zot, :xyz) # => nil + # + # params2 = ActionController::Parameters.new(foo: [10, 11, 12]) + # params2.dig(:foo, 1) # => 11 + def dig(*keys) + convert_value_to_parameters(@parameters.dig(*keys)) + end + end + # Returns a new <tt>ActionController::Parameters</tt> instance that # includes only the given +keys+. If the given +keys+ # don't exist, returns an empty hash. @@ -799,7 +814,8 @@ module ActionController # end # # In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you - # will need to specify which nested attributes should be whitelisted. + # will need to specify which nested attributes should be whitelisted. You might want + # to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information. # # class Person # has_many :pets @@ -819,7 +835,7 @@ module ActionController # # It's mandatory to specify the nested attributes that should be whitelisted. # # If you use `permit` with just the key that points to the nested attributes hash, # # it will return an empty hash. - # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ]) + # params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ]) # end # end # diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 700317614f..ecd21f29ce 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -428,7 +428,7 @@ module ActionController end alias xhr :xml_http_request - # Simulate a HTTP request to +action+ by specifying request method, + # Simulate an HTTP request to +action+ by specifying request method, # parameters and set/volley the response. # # - +action+: The controller action to call. |