actionpack 7.1.3 → 7.2.1.1
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 +82 -501
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +102 -98
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +70 -85
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +15 -7
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +74 -72
- data/lib/action_controller/base.rb +198 -126
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +188 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +210 -205
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +113 -107
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +108 -82
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -75
- data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +525 -480
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +42 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +146 -126
- data/lib/action_controller.rb +10 -3
- data/lib/action_dispatch/constants.rb +2 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +44 -38
- data/lib/action_dispatch/http/filter_parameters.rb +18 -9
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
- data/lib/action_dispatch/http/mime_type.rb +31 -24
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +20 -44
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +94 -75
- data/lib/action_dispatch/http/response.rb +73 -61
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +13 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
- data/lib/action_dispatch/middleware/executor.rb +8 -0
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -4
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -3
- data/lib/action_dispatch/routing/mapper.rb +671 -636
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +59 -45
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +10 -3
- data/lib/action_dispatch/system_testing/driver.rb +3 -1
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +8 -6
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +223 -222
- data/lib/action_dispatch/testing/request_encoder.rb +2 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +12 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -28
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +39 -16
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "abstract_controller/error"
|
4
6
|
require "active_support/configurable"
|
5
7
|
require "active_support/descendants_tracker"
|
@@ -26,12 +28,12 @@ module AbstractController
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
|
-
#
|
31
|
+
# # Abstract Controller Base
|
30
32
|
#
|
31
|
-
# AbstractController::Base is a low-level API. Nobody should be
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
33
|
+
# AbstractController::Base is a low-level API. Nobody should be using it
|
34
|
+
# directly, and subclasses (like ActionController::Base) are expected to provide
|
35
|
+
# their own `render` method, since rendering means different things depending on
|
36
|
+
# the context.
|
35
37
|
class Base
|
36
38
|
##
|
37
39
|
# Returns the body of the HTTP response sent by the controller.
|
@@ -52,27 +54,26 @@ module AbstractController
|
|
52
54
|
attr_reader :abstract
|
53
55
|
alias_method :abstract?, :abstract
|
54
56
|
|
55
|
-
# Define a controller as abstract. See internal_methods for more
|
56
|
-
# details.
|
57
|
+
# Define a controller as abstract. See internal_methods for more details.
|
57
58
|
def abstract!
|
58
59
|
@abstract = true
|
59
60
|
end
|
60
61
|
|
61
62
|
def inherited(klass) # :nodoc:
|
62
|
-
# Define the abstract ivar on subclasses so that we don't get
|
63
|
-
#
|
63
|
+
# Define the abstract ivar on subclasses so that we don't get uninitialized ivar
|
64
|
+
# warnings
|
64
65
|
unless klass.instance_variable_defined?(:@abstract)
|
65
66
|
klass.instance_variable_set(:@abstract, false)
|
66
67
|
end
|
67
68
|
super
|
68
69
|
end
|
69
70
|
|
70
|
-
# A list of all internal methods for a controller. This finds the first
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
71
|
+
# A list of all internal methods for a controller. This finds the first abstract
|
72
|
+
# superclass of a controller, and gets a list of all public instance methods on
|
73
|
+
# that abstract class. Public instance methods of a controller would normally be
|
74
|
+
# considered action methods, so methods declared on abstract classes are being
|
75
|
+
# removed. (ActionController::Metal and ActionController::Base are defined as
|
76
|
+
# abstract)
|
76
77
|
def internal_methods
|
77
78
|
controller = self
|
78
79
|
methods = []
|
@@ -85,18 +86,18 @@ module AbstractController
|
|
85
86
|
controller.public_instance_methods(true) - methods
|
86
87
|
end
|
87
88
|
|
88
|
-
# A list of method names that should be considered actions. This
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
89
|
+
# A list of method names that should be considered actions. This includes all
|
90
|
+
# public instance methods on a controller, less any internal methods (see
|
91
|
+
# internal_methods), adding back in any methods that are internal, but still
|
92
|
+
# exist on the class itself.
|
93
|
+
#
|
94
|
+
# #### Returns
|
95
|
+
# * `Set` - A set of all methods that should be considered actions.
|
93
96
|
#
|
94
|
-
# ==== Returns
|
95
|
-
# * <tt>Set</tt> - A set of all methods that should be considered actions.
|
96
97
|
def action_methods
|
97
98
|
@action_methods ||= begin
|
98
|
-
# All public instance methods of this class, including ancestors
|
99
|
-
#
|
99
|
+
# All public instance methods of this class, including ancestors except for
|
100
|
+
# public instance methods of Base and its ancestors.
|
100
101
|
methods = public_instance_methods(true) - internal_methods
|
101
102
|
# Be sure to include shadowed public instance methods of this class.
|
102
103
|
methods.concat(public_instance_methods(false))
|
@@ -105,23 +106,24 @@ module AbstractController
|
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
108
|
-
# action_methods are cached and there is sometimes a need to refresh
|
109
|
-
#
|
110
|
-
#
|
109
|
+
# action_methods are cached and there is sometimes a need to refresh them.
|
110
|
+
# ::clear_action_methods! allows you to do that, so next time you run
|
111
|
+
# action_methods, they will be recalculated.
|
111
112
|
def clear_action_methods!
|
112
113
|
@action_methods = nil
|
113
114
|
end
|
114
115
|
|
115
116
|
# Returns the full controller name, underscored, without the ending Controller.
|
116
117
|
#
|
117
|
-
#
|
118
|
+
# class MyApp::MyPostsController < AbstractController::Base
|
119
|
+
#
|
120
|
+
# end
|
118
121
|
#
|
119
|
-
#
|
122
|
+
# MyApp::MyPostsController.controller_path # => "my_app/my_posts"
|
120
123
|
#
|
121
|
-
#
|
124
|
+
# #### Returns
|
125
|
+
# * `String`
|
122
126
|
#
|
123
|
-
# ==== Returns
|
124
|
-
# * <tt>String</tt>
|
125
127
|
def controller_path
|
126
128
|
@controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
|
127
129
|
end
|
@@ -142,13 +144,14 @@ module AbstractController
|
|
142
144
|
|
143
145
|
# Calls the action going through the entire Action Dispatch stack.
|
144
146
|
#
|
145
|
-
# The actual method that is called is determined by calling
|
146
|
-
#
|
147
|
-
#
|
147
|
+
# The actual method that is called is determined by calling #method_for_action.
|
148
|
+
# If no method can handle the action, then an AbstractController::ActionNotFound
|
149
|
+
# error is raised.
|
148
150
|
#
|
149
|
-
#
|
150
|
-
# *
|
151
|
-
|
151
|
+
# #### Returns
|
152
|
+
# * `self`
|
153
|
+
#
|
154
|
+
def process(action, ...)
|
152
155
|
@_action_name = action.to_s
|
153
156
|
|
154
157
|
unless action_name = _find_action_name(@_action_name)
|
@@ -157,9 +160,8 @@ module AbstractController
|
|
157
160
|
|
158
161
|
@_response_body = nil
|
159
162
|
|
160
|
-
process_action(action_name,
|
163
|
+
process_action(action_name, ...)
|
161
164
|
end
|
162
|
-
ruby2_keywords(:process)
|
163
165
|
|
164
166
|
# Delegates to the class's ::controller_path.
|
165
167
|
def controller_path
|
@@ -171,31 +173,30 @@ module AbstractController
|
|
171
173
|
self.class.action_methods
|
172
174
|
end
|
173
175
|
|
174
|
-
# Returns true if a method for the action is available and
|
175
|
-
#
|
176
|
+
# Returns true if a method for the action is available and can be dispatched,
|
177
|
+
# false otherwise.
|
178
|
+
#
|
179
|
+
# Notice that `action_methods.include?("foo")` may return false and
|
180
|
+
# `available_action?("foo")` returns true because this method considers actions
|
181
|
+
# that are also available through other means, for example, implicit render
|
182
|
+
# ones.
|
176
183
|
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
# this method considers actions that are also available
|
180
|
-
# through other means, for example, implicit render ones.
|
184
|
+
# #### Parameters
|
185
|
+
# * `action_name` - The name of an action to be tested
|
181
186
|
#
|
182
|
-
# ==== Parameters
|
183
|
-
# * <tt>action_name</tt> - The name of an action to be tested
|
184
187
|
def available_action?(action_name)
|
185
188
|
_find_action_name(action_name)
|
186
189
|
end
|
187
190
|
|
188
|
-
# Tests if a response body is set. Used to determine if the
|
189
|
-
#
|
190
|
-
# AbstractController::Callbacks.
|
191
|
+
# Tests if a response body is set. Used to determine if the `process_action`
|
192
|
+
# callback needs to be terminated in AbstractController::Callbacks.
|
191
193
|
def performed?
|
192
194
|
response_body
|
193
195
|
end
|
194
196
|
|
195
|
-
# Returns true if the given controller is capable of rendering
|
196
|
-
#
|
197
|
-
#
|
198
|
-
# support paths, only full URLs.
|
197
|
+
# Returns true if the given controller is capable of rendering a path. A
|
198
|
+
# subclass of `AbstractController::Base` may return false. An Email controller
|
199
|
+
# for example does not support paths, only full URLs.
|
199
200
|
def self.supports_path?
|
200
201
|
true
|
201
202
|
end
|
@@ -205,80 +206,83 @@ module AbstractController
|
|
205
206
|
end
|
206
207
|
|
207
208
|
private
|
208
|
-
# Returns true if the name can be considered an action because
|
209
|
-
#
|
209
|
+
# Returns true if the name can be considered an action because it has a method
|
210
|
+
# defined in the controller.
|
211
|
+
#
|
212
|
+
# #### Parameters
|
213
|
+
# * `name` - The name of an action to be tested
|
210
214
|
#
|
211
|
-
# ==== Parameters
|
212
|
-
# * <tt>name</tt> - The name of an action to be tested
|
213
215
|
def action_method?(name)
|
214
216
|
self.class.action_methods.include?(name)
|
215
217
|
end
|
216
218
|
|
217
|
-
# Call the action. Override this in a subclass to modify the
|
218
|
-
#
|
219
|
-
#
|
219
|
+
# Call the action. Override this in a subclass to modify the behavior around
|
220
|
+
# processing an action. This, and not #process, is the intended way to override
|
221
|
+
# action dispatching.
|
220
222
|
#
|
221
|
-
# Notice that the first argument is the method to be dispatched
|
222
|
-
#
|
223
|
+
# Notice that the first argument is the method to be dispatched which is **not**
|
224
|
+
# necessarily the same as the action name.
|
223
225
|
def process_action(...)
|
224
226
|
send_action(...)
|
225
227
|
end
|
226
228
|
|
227
|
-
# Actually call the method associated with the action. Override
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
# method.
|
229
|
+
# Actually call the method associated with the action. Override this method if
|
230
|
+
# you wish to change how action methods are called, not to add additional
|
231
|
+
# behavior around it. For example, you would override #send_action if you want
|
232
|
+
# to inject arguments into the method.
|
232
233
|
alias send_action send
|
233
234
|
|
234
|
-
# If the action name was not found, but a method called "action_missing"
|
235
|
-
#
|
236
|
-
#
|
235
|
+
# If the action name was not found, but a method called "action_missing" was
|
236
|
+
# found, #method_for_action will return "_handle_action_missing". This method
|
237
|
+
# calls #action_missing with the current action name.
|
237
238
|
def _handle_action_missing(*args)
|
238
239
|
action_missing(@_action_name, *args)
|
239
240
|
end
|
240
241
|
|
241
|
-
# Takes an action name and returns the name of the method that will
|
242
|
-
#
|
242
|
+
# Takes an action name and returns the name of the method that will handle the
|
243
|
+
# action.
|
243
244
|
#
|
244
245
|
# It checks if the action name is valid and returns false otherwise.
|
245
246
|
#
|
246
247
|
# See method_for_action for more information.
|
247
248
|
#
|
248
|
-
#
|
249
|
-
# *
|
249
|
+
# #### Parameters
|
250
|
+
# * `action_name` - An action name to find a method name for
|
251
|
+
#
|
252
|
+
#
|
253
|
+
# #### Returns
|
254
|
+
# * `string` - The name of the method that handles the action
|
255
|
+
# * false - No valid method name could be found.
|
250
256
|
#
|
251
|
-
#
|
252
|
-
# * <tt>string</tt> - The name of the method that handles the action
|
253
|
-
# * false - No valid method name could be found.
|
254
|
-
# Raise +AbstractController::ActionNotFound+.
|
257
|
+
# Raise `AbstractController::ActionNotFound`.
|
255
258
|
def _find_action_name(action_name)
|
256
259
|
_valid_action_name?(action_name) && method_for_action(action_name)
|
257
260
|
end
|
258
261
|
|
259
|
-
# Takes an action name and returns the name of the method that will
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
263
|
-
#
|
262
|
+
# Takes an action name and returns the name of the method that will handle the
|
263
|
+
# action. In normal cases, this method returns the same name as it receives. By
|
264
|
+
# default, if #method_for_action receives a name that is not an action, it will
|
265
|
+
# look for an #action_missing method and return "_handle_action_missing" if one
|
266
|
+
# is found.
|
267
|
+
#
|
268
|
+
# Subclasses may override this method to add additional conditions that should
|
269
|
+
# be considered an action. For instance, an HTTP controller with a template
|
270
|
+
# matching the action name is considered to exist.
|
271
|
+
#
|
272
|
+
# If you override this method to handle additional cases, you may also provide a
|
273
|
+
# method (like `_handle_method_missing`) to handle the case.
|
264
274
|
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
# with a template matching the action name is considered to exist.
|
275
|
+
# If none of these conditions are true, and `method_for_action` returns `nil`,
|
276
|
+
# an `AbstractController::ActionNotFound` exception will be raised.
|
268
277
|
#
|
269
|
-
#
|
270
|
-
#
|
271
|
-
# the case.
|
278
|
+
# #### Parameters
|
279
|
+
# * `action_name` - An action name to find a method name for
|
272
280
|
#
|
273
|
-
# If none of these conditions are true, and +method_for_action+
|
274
|
-
# returns +nil+, an +AbstractController::ActionNotFound+ exception will be raised.
|
275
281
|
#
|
276
|
-
#
|
277
|
-
# *
|
282
|
+
# #### Returns
|
283
|
+
# * `string` - The name of the method that handles the action
|
284
|
+
# * `nil` - No method name could be found.
|
278
285
|
#
|
279
|
-
# ==== Returns
|
280
|
-
# * <tt>string</tt> - The name of the method that handles the action
|
281
|
-
# * <tt>nil</tt> - No method name could be found.
|
282
286
|
def method_for_action(action_name)
|
283
287
|
if action_method?(action_name)
|
284
288
|
action_name
|
@@ -1,22 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module AbstractController
|
4
6
|
module Caching
|
5
|
-
#
|
7
|
+
# # Abstract Controller Caching Fragments
|
6
8
|
#
|
7
|
-
# Fragment caching is used for caching various blocks within
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# the +cache+ helper available in the Action View. See
|
9
|
+
# Fragment caching is used for caching various blocks within views without
|
10
|
+
# caching the entire action as a whole. This is useful when certain elements of
|
11
|
+
# an action change frequently or depend on complicated state while other parts
|
12
|
+
# rarely change or can be shared amongst multiple parties. The caching is done
|
13
|
+
# using the `cache` helper available in the Action View. See
|
13
14
|
# ActionView::Helpers::CacheHelper for more information.
|
14
15
|
#
|
15
|
-
# While it's strongly recommended that you use key-based cache
|
16
|
-
#
|
17
|
-
#
|
16
|
+
# While it's strongly recommended that you use key-based cache expiration (see
|
17
|
+
# links in CacheHelper for more information), it is also possible to manually
|
18
|
+
# expire caches. For example:
|
18
19
|
#
|
19
|
-
#
|
20
|
+
# expire_fragment('name_of_cache')
|
20
21
|
module Fragments
|
21
22
|
extend ActiveSupport::Concern
|
22
23
|
|
@@ -35,38 +36,35 @@ module AbstractController
|
|
35
36
|
end
|
36
37
|
|
37
38
|
module ClassMethods
|
38
|
-
# Allows you to specify controller-wide key prefixes for
|
39
|
-
#
|
40
|
-
#
|
39
|
+
# Allows you to specify controller-wide key prefixes for cache fragments. Pass
|
40
|
+
# either a constant `value`, or a block which computes a value each time a cache
|
41
|
+
# key is generated.
|
41
42
|
#
|
42
|
-
# For example, you may want to prefix all fragment cache keys
|
43
|
-
#
|
44
|
-
# invalidate all caches.
|
43
|
+
# For example, you may want to prefix all fragment cache keys with a global
|
44
|
+
# version identifier, so you can easily invalidate all caches.
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
46
|
+
# class ApplicationController
|
47
|
+
# fragment_cache_key "v1"
|
48
|
+
# end
|
49
49
|
#
|
50
|
-
# When it's time to invalidate all fragments, simply change
|
51
|
-
#
|
52
|
-
# invalidation using a computed value:
|
50
|
+
# When it's time to invalidate all fragments, simply change the string constant.
|
51
|
+
# Or, progressively roll out the cache invalidation using a computed value:
|
53
52
|
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
53
|
+
# class ApplicationController
|
54
|
+
# fragment_cache_key do
|
55
|
+
# @account.id.odd? ? "v1" : "v2"
|
56
|
+
# end
|
57
57
|
# end
|
58
|
-
# end
|
59
58
|
def fragment_cache_key(value = nil, &key)
|
60
59
|
self.fragment_cache_keys += [key || -> { value }]
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
64
|
-
# Given a key (as described in
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# with the specified +key+ value.
|
63
|
+
# Given a key (as described in `expire_fragment`), returns a key array suitable
|
64
|
+
# for use in reading, writing, or expiring a cached fragment. All keys begin
|
65
|
+
# with `:views`, followed by `ENV["RAILS_CACHE_ID"]` or
|
66
|
+
# `ENV["RAILS_APP_VERSION"]` if set, followed by any controller-wide key prefix
|
67
|
+
# values, ending with the specified `key` value.
|
70
68
|
def combined_fragment_cache_key(key)
|
71
69
|
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
72
70
|
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
@@ -77,8 +75,8 @@ module AbstractController
|
|
77
75
|
cache_key
|
78
76
|
end
|
79
77
|
|
80
|
-
# Writes
|
81
|
-
#
|
78
|
+
# Writes `content` to the location signified by `key` (see `expire_fragment` for
|
79
|
+
# acceptable formats).
|
82
80
|
def write_fragment(key, content, options = nil)
|
83
81
|
return content unless cache_configured?
|
84
82
|
|
@@ -90,8 +88,8 @@ module AbstractController
|
|
90
88
|
content
|
91
89
|
end
|
92
90
|
|
93
|
-
# Reads a cached fragment from the location signified by
|
94
|
-
#
|
91
|
+
# Reads a cached fragment from the location signified by `key` (see
|
92
|
+
# `expire_fragment` for acceptable formats).
|
95
93
|
def read_fragment(key, options = nil)
|
96
94
|
return unless cache_configured?
|
97
95
|
|
@@ -102,8 +100,8 @@ module AbstractController
|
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
|
-
# Check if a cached fragment from the location signified by
|
106
|
-
#
|
103
|
+
# Check if a cached fragment from the location signified by `key` exists (see
|
104
|
+
# `expire_fragment` for acceptable formats).
|
107
105
|
def fragment_exist?(key, options = nil)
|
108
106
|
return unless cache_configured?
|
109
107
|
key = combined_fragment_cache_key(key)
|
@@ -115,22 +113,21 @@ module AbstractController
|
|
115
113
|
|
116
114
|
# Removes fragments from the cache.
|
117
115
|
#
|
118
|
-
#
|
116
|
+
# `key` can take one of three forms:
|
117
|
+
#
|
118
|
+
# * String - This would normally take the form of a path, like
|
119
|
+
# `pages/45/notes`.
|
120
|
+
# * Hash - Treated as an implicit call to `url_for`, like `{ controller:
|
121
|
+
# 'pages', action: 'notes', id: 45}`
|
122
|
+
# * Regexp - Will remove any fragment that matches, so `%r{pages/\d*/notes}`
|
123
|
+
# might remove all notes. Make sure you don't use anchors in the regex (`^`
|
124
|
+
# or `$`) because the actual filename matched looks like
|
125
|
+
# `./cache/filename/path.cache`. Note: Regexp expiration is only supported
|
126
|
+
# on caches that can iterate over all keys (unlike memcached).
|
119
127
|
#
|
120
|
-
# * String - This would normally take the form of a path, like
|
121
|
-
# <tt>pages/45/notes</tt>.
|
122
|
-
# * Hash - Treated as an implicit call to +url_for+, like
|
123
|
-
# <tt>{ controller: 'pages', action: 'notes', id: 45}</tt>
|
124
|
-
# * Regexp - Will remove any fragment that matches, so
|
125
|
-
# <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you
|
126
|
-
# don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because
|
127
|
-
# the actual filename matched looks like
|
128
|
-
# <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is
|
129
|
-
# only supported on caches that can iterate over all keys (unlike
|
130
|
-
# memcached).
|
131
128
|
#
|
132
|
-
#
|
133
|
-
#
|
129
|
+
# `options` is passed through to the cache store's `delete` method (or
|
130
|
+
# `delete_matched`, for Regexp keys).
|
134
131
|
def expire_fragment(key, options = nil)
|
135
132
|
return unless cache_configured?
|
136
133
|
key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
|