aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb14
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb87
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb1
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb2
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb8
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb20
-rw-r--r--actionpack/lib/action_controller/test_case.rb2
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.