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.
- 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)
|