actionpack 4.2.11.1 → 6.1.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +291 -489
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +102 -120
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +83 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +296 -422
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +107 -56
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +79 -51
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +90 -43
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +78 -48
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -23,36 +23,36 @@ by default and Action View rendering is implicitly triggered by Action
|
|
23
23
|
Controller. However, these modules are designed to function on their own and
|
24
24
|
can be used outside of Rails.
|
25
25
|
|
26
|
+
You can read more about Action Pack in the {Action Controller Overview}[https://guides.rubyonrails.org/action_controller_overview.html] guide.
|
26
27
|
|
27
28
|
== Download and installation
|
28
29
|
|
29
30
|
The latest version of Action Pack can be installed with RubyGems:
|
30
31
|
|
31
|
-
|
32
|
+
$ gem install actionpack
|
32
33
|
|
33
|
-
Source code can be downloaded as part of the Rails project on GitHub
|
34
|
+
Source code can be downloaded as part of the Rails project on GitHub:
|
34
35
|
|
35
|
-
* https://github.com/rails/rails/tree/
|
36
|
+
* https://github.com/rails/rails/tree/main/actionpack
|
36
37
|
|
37
38
|
|
38
39
|
== License
|
39
40
|
|
40
41
|
Action Pack is released under the MIT license:
|
41
42
|
|
42
|
-
*
|
43
|
+
* https://opensource.org/licenses/MIT
|
43
44
|
|
44
45
|
|
45
46
|
== Support
|
46
47
|
|
47
|
-
API documentation is at
|
48
|
+
API documentation is at:
|
48
49
|
|
49
|
-
*
|
50
|
+
* https://api.rubyonrails.org
|
50
51
|
|
51
|
-
Bug reports
|
52
|
+
Bug reports for the Ruby on Rails project can be filed here:
|
52
53
|
|
53
54
|
* https://github.com/rails/rails/issues
|
54
55
|
|
55
56
|
Feature requests should be discussed on the rails-core mailing list here:
|
56
57
|
|
57
|
-
* https://
|
58
|
-
|
58
|
+
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
@@ -1,30 +1,65 @@
|
|
1
|
-
|
2
|
-
require 'set'
|
3
|
-
require 'active_support/configurable'
|
4
|
-
require 'active_support/descendants_tracker'
|
5
|
-
require 'active_support/core_ext/module/anonymous'
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
require "abstract_controller/error"
|
4
|
+
require "active_support/configurable"
|
5
|
+
require "active_support/descendants_tracker"
|
6
|
+
require "active_support/core_ext/module/anonymous"
|
7
|
+
require "active_support/core_ext/module/attr_internal"
|
10
8
|
|
9
|
+
module AbstractController
|
11
10
|
# Raised when a non-existing controller action is triggered.
|
12
11
|
class ActionNotFound < StandardError
|
12
|
+
attr_reader :controller, :action
|
13
|
+
def initialize(message = nil, controller = nil, action = nil)
|
14
|
+
@controller = controller
|
15
|
+
@action = action
|
16
|
+
super(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
class Correction
|
20
|
+
def initialize(error)
|
21
|
+
@error = error
|
22
|
+
end
|
23
|
+
|
24
|
+
def corrections
|
25
|
+
if @error.action
|
26
|
+
maybe_these = @error.controller.class.action_methods
|
27
|
+
|
28
|
+
maybe_these.sort_by { |n|
|
29
|
+
DidYouMean::Jaro.distance(@error.action.to_s, n)
|
30
|
+
}.reverse.first(4)
|
31
|
+
else
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
38
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
39
|
+
DidYouMean.correct_error(self, Correction)
|
40
|
+
end
|
13
41
|
end
|
14
42
|
|
15
|
-
#
|
43
|
+
# AbstractController::Base is a low-level API. Nobody should be
|
16
44
|
# using it directly, and subclasses (like ActionController::Base) are
|
17
45
|
# expected to provide their own +render+ method, since rendering means
|
18
46
|
# different things depending on the context.
|
19
47
|
class Base
|
48
|
+
##
|
49
|
+
# Returns the body of the HTTP response sent by the controller.
|
20
50
|
attr_internal :response_body
|
51
|
+
|
52
|
+
##
|
53
|
+
# Returns the name of the action this controller is processing.
|
21
54
|
attr_internal :action_name
|
55
|
+
|
56
|
+
##
|
57
|
+
# Returns the formats that can be processed by the controller.
|
22
58
|
attr_internal :formats
|
23
59
|
|
24
60
|
include ActiveSupport::Configurable
|
25
61
|
extend ActiveSupport::DescendantsTracker
|
26
62
|
|
27
|
-
undef_method :not_implemented
|
28
63
|
class << self
|
29
64
|
attr_reader :abstract
|
30
65
|
alias_method :abstract?, :abstract
|
@@ -49,7 +84,7 @@ module AbstractController
|
|
49
84
|
# instance methods on that abstract class. Public instance methods of
|
50
85
|
# a controller would normally be considered action methods, so methods
|
51
86
|
# declared on abstract classes are being removed.
|
52
|
-
# (ActionController::Metal and ActionController::Base are defined as abstract)
|
87
|
+
# (<tt>ActionController::Metal</tt> and ActionController::Base are defined as abstract)
|
53
88
|
def internal_methods
|
54
89
|
controller = self
|
55
90
|
|
@@ -57,21 +92,11 @@ module AbstractController
|
|
57
92
|
controller.public_instance_methods(true)
|
58
93
|
end
|
59
94
|
|
60
|
-
# The list of hidden actions. Defaults to an empty array.
|
61
|
-
# This can be modified by other modules or subclasses
|
62
|
-
# to specify particular actions as hidden.
|
63
|
-
#
|
64
|
-
# ==== Returns
|
65
|
-
# * <tt>Array</tt> - An array of method names that should not be considered actions.
|
66
|
-
def hidden_actions
|
67
|
-
[]
|
68
|
-
end
|
69
|
-
|
70
95
|
# A list of method names that should be considered actions. This
|
71
96
|
# includes all public instance methods on a controller, less
|
72
|
-
# any internal methods (see
|
97
|
+
# any internal methods (see internal_methods), adding back in
|
73
98
|
# any methods that are internal, but still exist on the class
|
74
|
-
# itself.
|
99
|
+
# itself.
|
75
100
|
#
|
76
101
|
# ==== Returns
|
77
102
|
# * <tt>Set</tt> - A set of all methods that should be considered actions.
|
@@ -82,30 +107,33 @@ module AbstractController
|
|
82
107
|
# Except for public instance methods of Base and its ancestors
|
83
108
|
internal_methods +
|
84
109
|
# Be sure to include shadowed public instance methods of this class
|
85
|
-
public_instance_methods(false))
|
86
|
-
# And always exclude explicitly hidden actions
|
87
|
-
hidden_actions.to_a
|
110
|
+
public_instance_methods(false))
|
88
111
|
|
89
|
-
|
90
|
-
|
112
|
+
methods.map!(&:to_s)
|
113
|
+
|
114
|
+
methods.to_set
|
91
115
|
end
|
92
116
|
end
|
93
117
|
|
94
|
-
# action_methods are cached and there is sometimes need to refresh
|
95
|
-
# them. clear_action_methods! allows you to do that, so next time
|
96
|
-
# you run action_methods, they will be recalculated
|
118
|
+
# action_methods are cached and there is sometimes a need to refresh
|
119
|
+
# them. ::clear_action_methods! allows you to do that, so next time
|
120
|
+
# you run action_methods, they will be recalculated.
|
97
121
|
def clear_action_methods!
|
98
122
|
@action_methods = nil
|
99
123
|
end
|
100
124
|
|
101
125
|
# Returns the full controller name, underscored, without the ending Controller.
|
102
|
-
#
|
103
|
-
#
|
126
|
+
#
|
127
|
+
# class MyApp::MyPostsController < AbstractController::Base
|
128
|
+
#
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# MyApp::MyPostsController.controller_path # => "my_app/my_posts"
|
104
132
|
#
|
105
133
|
# ==== Returns
|
106
134
|
# * <tt>String</tt>
|
107
135
|
def controller_path
|
108
|
-
@controller_path ||= name.
|
136
|
+
@controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
|
109
137
|
end
|
110
138
|
|
111
139
|
# Refresh the cached action_methods when a new action_method is added.
|
@@ -129,7 +157,7 @@ module AbstractController
|
|
129
157
|
@_action_name = action.to_s
|
130
158
|
|
131
159
|
unless action_name = _find_action_name(@_action_name)
|
132
|
-
raise ActionNotFound
|
160
|
+
raise ActionNotFound.new("The action '#{action}' could not be found for #{self.class.name}", self, action)
|
133
161
|
end
|
134
162
|
|
135
163
|
@_response_body = nil
|
@@ -137,12 +165,12 @@ module AbstractController
|
|
137
165
|
process_action(action_name, *args)
|
138
166
|
end
|
139
167
|
|
140
|
-
# Delegates to the class'
|
168
|
+
# Delegates to the class' ::controller_path
|
141
169
|
def controller_path
|
142
170
|
self.class.controller_path
|
143
171
|
end
|
144
172
|
|
145
|
-
# Delegates to the class'
|
173
|
+
# Delegates to the class' ::action_methods
|
146
174
|
def action_methods
|
147
175
|
self.class.action_methods
|
148
176
|
end
|
@@ -157,11 +185,15 @@ module AbstractController
|
|
157
185
|
#
|
158
186
|
# ==== Parameters
|
159
187
|
# * <tt>action_name</tt> - The name of an action to be tested
|
160
|
-
#
|
161
|
-
# ==== Returns
|
162
|
-
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
|
163
188
|
def available_action?(action_name)
|
164
|
-
_find_action_name(action_name)
|
189
|
+
_find_action_name(action_name)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Tests if a response body is set. Used to determine if the
|
193
|
+
# +process_action+ callback needs to be terminated in
|
194
|
+
# +AbstractController::Callbacks+.
|
195
|
+
def performed?
|
196
|
+
response_body
|
165
197
|
end
|
166
198
|
|
167
199
|
# Returns true if the given controller is capable of rendering
|
@@ -172,18 +204,16 @@ module AbstractController
|
|
172
204
|
true
|
173
205
|
end
|
174
206
|
|
175
|
-
|
207
|
+
def inspect # :nodoc:
|
208
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
|
209
|
+
end
|
176
210
|
|
211
|
+
private
|
177
212
|
# Returns true if the name can be considered an action because
|
178
213
|
# it has a method defined in the controller.
|
179
214
|
#
|
180
215
|
# ==== Parameters
|
181
216
|
# * <tt>name</tt> - The name of an action to be tested
|
182
|
-
#
|
183
|
-
# ==== Returns
|
184
|
-
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
|
185
|
-
#
|
186
|
-
# :api: private
|
187
217
|
def action_method?(name)
|
188
218
|
self.class.action_methods.include?(name)
|
189
219
|
end
|
@@ -225,7 +255,7 @@ module AbstractController
|
|
225
255
|
# ==== Returns
|
226
256
|
# * <tt>string</tt> - The name of the method that handles the action
|
227
257
|
# * false - No valid method name could be found.
|
228
|
-
# Raise AbstractController::ActionNotFound
|
258
|
+
# Raise +AbstractController::ActionNotFound+.
|
229
259
|
def _find_action_name(action_name)
|
230
260
|
_valid_action_name?(action_name) && method_for_action(action_name)
|
231
261
|
end
|
@@ -241,11 +271,11 @@ module AbstractController
|
|
241
271
|
# with a template matching the action name is considered to exist.
|
242
272
|
#
|
243
273
|
# If you override this method to handle additional cases, you may
|
244
|
-
# also provide a method (like _handle_method_missing) to handle
|
274
|
+
# also provide a method (like +_handle_method_missing+) to handle
|
245
275
|
# the case.
|
246
276
|
#
|
247
|
-
# If none of these conditions are true, and method_for_action
|
248
|
-
# returns nil
|
277
|
+
# If none of these conditions are true, and +method_for_action+
|
278
|
+
# returns +nil+, an +AbstractController::ActionNotFound+ exception will be raised.
|
249
279
|
#
|
250
280
|
# ==== Parameters
|
251
281
|
# * <tt>action_name</tt> - An action name to find a method name for
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractController
|
2
4
|
module Caching
|
3
5
|
# Fragment caching is used for caching various blocks within
|
4
6
|
# views without caching the entire action as a whole. This is
|
@@ -14,12 +16,63 @@ module ActionController
|
|
14
16
|
#
|
15
17
|
# expire_fragment('name_of_cache')
|
16
18
|
module Fragments
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
included do
|
22
|
+
if respond_to?(:class_attribute)
|
23
|
+
class_attribute :fragment_cache_keys
|
24
|
+
else
|
25
|
+
mattr_writer :fragment_cache_keys
|
26
|
+
end
|
27
|
+
|
28
|
+
self.fragment_cache_keys = []
|
29
|
+
|
30
|
+
if respond_to?(:helper_method)
|
31
|
+
helper_method :combined_fragment_cache_key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# Allows you to specify controller-wide key prefixes for
|
37
|
+
# cache fragments. Pass either a constant +value+, or a block
|
38
|
+
# which computes a value each time a cache key is generated.
|
39
|
+
#
|
40
|
+
# For example, you may want to prefix all fragment cache keys
|
41
|
+
# with a global version identifier, so you can easily
|
42
|
+
# invalidate all caches.
|
43
|
+
#
|
44
|
+
# class ApplicationController
|
45
|
+
# fragment_cache_key "v1"
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# When it's time to invalidate all fragments, simply change
|
49
|
+
# the string constant. Or, progressively roll out the cache
|
50
|
+
# invalidation using a computed value:
|
51
|
+
#
|
52
|
+
# class ApplicationController
|
53
|
+
# fragment_cache_key do
|
54
|
+
# @account.id.odd? ? "v1" : "v2"
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
def fragment_cache_key(value = nil, &key)
|
58
|
+
self.fragment_cache_keys += [key || -> { value }]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
17
62
|
# Given a key (as described in +expire_fragment+), returns
|
18
|
-
# a key suitable for use in reading, writing, or expiring a
|
19
|
-
# cached fragment. All keys
|
20
|
-
#
|
21
|
-
|
22
|
-
|
63
|
+
# a key array suitable for use in reading, writing, or expiring a
|
64
|
+
# cached fragment. All keys begin with <tt>:views</tt>,
|
65
|
+
# followed by <tt>ENV["RAILS_CACHE_ID"]</tt> or <tt>ENV["RAILS_APP_VERSION"]</tt> if set,
|
66
|
+
# followed by any controller-wide key prefix values, ending
|
67
|
+
# with the specified +key+ value.
|
68
|
+
def combined_fragment_cache_key(key)
|
69
|
+
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
70
|
+
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
71
|
+
|
72
|
+
cache_key = [:views, ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"], head, tail]
|
73
|
+
cache_key.flatten!(1)
|
74
|
+
cache_key.compact!
|
75
|
+
cache_key
|
23
76
|
end
|
24
77
|
|
25
78
|
# Writes +content+ to the location signified by
|
@@ -27,7 +80,7 @@ module ActionController
|
|
27
80
|
def write_fragment(key, content, options = nil)
|
28
81
|
return content unless cache_configured?
|
29
82
|
|
30
|
-
key =
|
83
|
+
key = combined_fragment_cache_key(key)
|
31
84
|
instrument_fragment_cache :write_fragment, key do
|
32
85
|
content = content.to_str
|
33
86
|
cache_store.write(key, content, options)
|
@@ -40,7 +93,7 @@ module ActionController
|
|
40
93
|
def read_fragment(key, options = nil)
|
41
94
|
return unless cache_configured?
|
42
95
|
|
43
|
-
key =
|
96
|
+
key = combined_fragment_cache_key(key)
|
44
97
|
instrument_fragment_cache :read_fragment, key do
|
45
98
|
result = cache_store.read(key, options)
|
46
99
|
result.respond_to?(:html_safe) ? result.html_safe : result
|
@@ -51,7 +104,7 @@ module ActionController
|
|
51
104
|
# +key+ exists (see +expire_fragment+ for acceptable formats).
|
52
105
|
def fragment_exist?(key, options = nil)
|
53
106
|
return unless cache_configured?
|
54
|
-
key =
|
107
|
+
key = combined_fragment_cache_key(key)
|
55
108
|
|
56
109
|
instrument_fragment_cache :exist_fragment?, key do
|
57
110
|
cache_store.exist?(key, options)
|
@@ -78,7 +131,7 @@ module ActionController
|
|
78
131
|
# method (or <tt>delete_matched</tt>, for Regexp keys).
|
79
132
|
def expire_fragment(key, options = nil)
|
80
133
|
return unless cache_configured?
|
81
|
-
key =
|
134
|
+
key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
|
82
135
|
|
83
136
|
instrument_fragment_cache :expire_fragment, key do
|
84
137
|
if key.is_a?(Regexp)
|
@@ -90,13 +143,7 @@ module ActionController
|
|
90
143
|
end
|
91
144
|
|
92
145
|
def instrument_fragment_cache(name, key) # :nodoc:
|
93
|
-
|
94
|
-
controller: controller_name,
|
95
|
-
action: action_name,
|
96
|
-
key: key
|
97
|
-
}
|
98
|
-
|
99
|
-
ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
|
146
|
+
ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", instrument_payload(key)) { yield }
|
100
147
|
end
|
101
148
|
end
|
102
149
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractController
|
4
|
+
module Caching
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
eager_autoload do
|
9
|
+
autoload :Fragments
|
10
|
+
end
|
11
|
+
|
12
|
+
module ConfigMethods
|
13
|
+
def cache_store
|
14
|
+
config.cache_store
|
15
|
+
end
|
16
|
+
|
17
|
+
def cache_store=(store)
|
18
|
+
config.cache_store = ActiveSupport::Cache.lookup_store(*store)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def cache_configured?
|
23
|
+
perform_caching && cache_store
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include ConfigMethods
|
28
|
+
include AbstractController::Caching::Fragments
|
29
|
+
|
30
|
+
included do
|
31
|
+
extend ConfigMethods
|
32
|
+
|
33
|
+
config_accessor :default_static_extension
|
34
|
+
self.default_static_extension ||= ".html"
|
35
|
+
|
36
|
+
config_accessor :perform_caching
|
37
|
+
self.perform_caching = true if perform_caching.nil?
|
38
|
+
|
39
|
+
config_accessor :enable_fragment_cache_logging
|
40
|
+
self.enable_fragment_cache_logging = false
|
41
|
+
|
42
|
+
class_attribute :_view_cache_dependencies, default: []
|
43
|
+
helper_method :view_cache_dependencies if respond_to?(:helper_method)
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def view_cache_dependency(&dependency)
|
48
|
+
self._view_cache_dependencies += [dependency]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def view_cache_dependencies
|
53
|
+
self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
# Convenience accessor.
|
58
|
+
def cache(key, options = {}, &block) # :doc:
|
59
|
+
if cache_configured?
|
60
|
+
cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
|
61
|
+
else
|
62
|
+
yield
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,4 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AbstractController
|
4
|
+
# = Abstract Controller Callbacks
|
5
|
+
#
|
6
|
+
# Abstract Controller provides hooks during the life cycle of a controller action.
|
7
|
+
# Callbacks allow you to trigger logic during this cycle. Available callbacks are:
|
8
|
+
#
|
9
|
+
# * <tt>after_action</tt>
|
10
|
+
# * <tt>append_after_action</tt>
|
11
|
+
# * <tt>append_around_action</tt>
|
12
|
+
# * <tt>append_before_action</tt>
|
13
|
+
# * <tt>around_action</tt>
|
14
|
+
# * <tt>before_action</tt>
|
15
|
+
# * <tt>prepend_after_action</tt>
|
16
|
+
# * <tt>prepend_around_action</tt>
|
17
|
+
# * <tt>prepend_before_action</tt>
|
18
|
+
# * <tt>skip_after_action</tt>
|
19
|
+
# * <tt>skip_around_action</tt>
|
20
|
+
# * <tt>skip_before_action</tt>
|
21
|
+
#
|
22
|
+
# NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
|
23
|
+
#
|
2
24
|
module Callbacks
|
3
25
|
extend ActiveSupport::Concern
|
4
26
|
|
@@ -9,53 +31,51 @@ module AbstractController
|
|
9
31
|
|
10
32
|
included do
|
11
33
|
define_callbacks :process_action,
|
12
|
-
terminator: ->(controller,
|
34
|
+
terminator: ->(controller, result_lambda) { result_lambda.call; controller.performed? },
|
13
35
|
skip_after_callbacks_if_terminated: true
|
14
36
|
end
|
15
37
|
|
16
|
-
# Override AbstractController::Base
|
17
|
-
# process_action callbacks around the normal behavior.
|
18
|
-
def process_action(*
|
38
|
+
# Override <tt>AbstractController::Base#process_action</tt> to run the
|
39
|
+
# <tt>process_action</tt> callbacks around the normal behavior.
|
40
|
+
def process_action(*)
|
19
41
|
run_callbacks(:process_action) do
|
20
42
|
super
|
21
43
|
end
|
22
44
|
end
|
23
45
|
|
24
46
|
module ClassMethods
|
25
|
-
# If
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
47
|
+
# If +:only+ or +:except+ are used, convert the options into the
|
48
|
+
# +:if+ and +:unless+ options of ActiveSupport::Callbacks.
|
49
|
+
#
|
50
|
+
# The basic idea is that <tt>:only => :index</tt> gets converted to
|
51
|
+
# <tt>:if => proc {|c| c.action_name == "index" }</tt>.
|
52
|
+
#
|
53
|
+
# Note that <tt>:only</tt> has priority over <tt>:if</tt> in case they
|
54
|
+
# are used together.
|
55
|
+
#
|
56
|
+
# only: :index, if: -> { true } # the :if option will be ignored.
|
57
|
+
#
|
58
|
+
# Note that <tt>:if</tt> has priority over <tt>:except</tt> in case they
|
59
|
+
# are used together.
|
60
|
+
#
|
61
|
+
# except: :index, if: -> { true } # the :except option will be ignored.
|
29
62
|
#
|
30
63
|
# ==== Options
|
31
|
-
# * <tt>only</tt> - The callback should be run only for this action
|
32
|
-
# * <tt>except</tt> - The callback should be run for all actions except this action
|
64
|
+
# * <tt>only</tt> - The callback should be run only for this action.
|
65
|
+
# * <tt>except</tt> - The callback should be run for all actions except this action.
|
33
66
|
def _normalize_callback_options(options)
|
34
67
|
_normalize_callback_option(options, :only, :if)
|
35
68
|
_normalize_callback_option(options, :except, :unless)
|
36
69
|
end
|
37
70
|
|
38
71
|
def _normalize_callback_option(options, from, to) # :nodoc:
|
39
|
-
if from = options
|
40
|
-
|
72
|
+
if from = options.delete(from)
|
73
|
+
_from = Array(from).map(&:to_s).to_set
|
74
|
+
from = proc { |c| _from.include? c.action_name }
|
41
75
|
options[to] = Array(options[to]).unshift(from)
|
42
76
|
end
|
43
77
|
end
|
44
78
|
|
45
|
-
# Skip before, after, and around action callbacks matching any of the names.
|
46
|
-
#
|
47
|
-
# ==== Parameters
|
48
|
-
# * <tt>names</tt> - A list of valid names that could be used for
|
49
|
-
# callbacks. Note that skipping uses Ruby equality, so it's
|
50
|
-
# impossible to skip a callback defined using an anonymous proc
|
51
|
-
# using #skip_action_callback
|
52
|
-
def skip_action_callback(*names)
|
53
|
-
skip_before_action(*names)
|
54
|
-
skip_after_action(*names)
|
55
|
-
skip_around_action(*names)
|
56
|
-
end
|
57
|
-
alias_method :skip_filter, :skip_action_callback
|
58
|
-
|
59
79
|
# Take callback names and an optional callback proc, normalize them,
|
60
80
|
# then call the block with each callback. This allows us to abstract
|
61
81
|
# the normalization across several methods that use it.
|
@@ -66,8 +86,8 @@ module AbstractController
|
|
66
86
|
# * <tt>block</tt> - A proc that should be added to the callbacks.
|
67
87
|
#
|
68
88
|
# ==== Block Parameters
|
69
|
-
# * <tt>name</tt> - The callback to be added
|
70
|
-
# * <tt>options</tt> - A hash of options to be used when adding the callback
|
89
|
+
# * <tt>name</tt> - The callback to be added.
|
90
|
+
# * <tt>options</tt> - A hash of options to be used when adding the callback.
|
71
91
|
def _insert_callbacks(callbacks, block = nil)
|
72
92
|
options = callbacks.extract_options!
|
73
93
|
_normalize_callback_options(options)
|
@@ -83,6 +103,10 @@ module AbstractController
|
|
83
103
|
# :call-seq: before_action(names, block)
|
84
104
|
#
|
85
105
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
106
|
+
#
|
107
|
+
# If the callback renders or redirects, the action will not run. If there
|
108
|
+
# are additional callbacks scheduled to run after that callback, they are
|
109
|
+
# also cancelled.
|
86
110
|
|
87
111
|
##
|
88
112
|
# :method: prepend_before_action
|
@@ -90,6 +114,10 @@ module AbstractController
|
|
90
114
|
# :call-seq: prepend_before_action(names, block)
|
91
115
|
#
|
92
116
|
# Prepend a callback before actions. See _insert_callbacks for parameter details.
|
117
|
+
#
|
118
|
+
# If the callback renders or redirects, the action will not run. If there
|
119
|
+
# are additional callbacks scheduled to run after that callback, they are
|
120
|
+
# also cancelled.
|
93
121
|
|
94
122
|
##
|
95
123
|
# :method: skip_before_action
|
@@ -104,6 +132,10 @@ module AbstractController
|
|
104
132
|
# :call-seq: append_before_action(names, block)
|
105
133
|
#
|
106
134
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
135
|
+
#
|
136
|
+
# If the callback renders or redirects, the action will not run. If there
|
137
|
+
# are additional callbacks scheduled to run after that callback, they are
|
138
|
+
# also cancelled.
|
107
139
|
|
108
140
|
##
|
109
141
|
# :method: after_action
|
@@ -169,14 +201,12 @@ module AbstractController
|
|
169
201
|
set_callback(:process_action, callback, name, options)
|
170
202
|
end
|
171
203
|
end
|
172
|
-
alias_method :"#{callback}_filter", :"#{callback}_action"
|
173
204
|
|
174
205
|
define_method "prepend_#{callback}_action" do |*names, &blk|
|
175
206
|
_insert_callbacks(names, blk) do |name, options|
|
176
|
-
set_callback(:process_action, callback, name, options.merge(:
|
207
|
+
set_callback(:process_action, callback, name, options.merge(prepend: true))
|
177
208
|
end
|
178
209
|
end
|
179
|
-
alias_method :"prepend_#{callback}_filter", :"prepend_#{callback}_action"
|
180
210
|
|
181
211
|
# Skip a before, after or around callback. See _insert_callbacks
|
182
212
|
# for details on the allowed parameters.
|
@@ -185,11 +215,9 @@ module AbstractController
|
|
185
215
|
skip_callback(:process_action, callback, name, options)
|
186
216
|
end
|
187
217
|
end
|
188
|
-
alias_method :"skip_#{callback}_filter", :"skip_#{callback}_action"
|
189
218
|
|
190
219
|
# *_action is the same as append_*_action
|
191
220
|
alias_method :"append_#{callback}_action", :"#{callback}_action"
|
192
|
-
alias_method :"append_#{callback}_filter", :"#{callback}_action"
|
193
221
|
end
|
194
222
|
end
|
195
223
|
end
|