actionpack 7.0.8.7 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +90 -537
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +119 -106
- data/lib/abstract_controller/caching/fragments.rb +51 -52
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +94 -67
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +121 -91
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +14 -13
- data/lib/abstract_controller/translation.rb +12 -30
- data/lib/abstract_controller/url_for.rb +9 -5
- data/lib/abstract_controller.rb +8 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +78 -73
- data/lib/action_controller/base.rb +199 -141
- data/lib/action_controller/caching.rb +16 -11
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +21 -16
- data/lib/action_controller/log_subscriber.rb +19 -5
- 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 +187 -174
- data/lib/action_controller/metal/content_security_policy.rb +26 -25
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +65 -54
- data/lib/action_controller/metal/default_headers.rb +6 -2
- data/lib/action_controller/metal/etag_with_flash.rb +4 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +18 -14
- data/lib/action_controller/metal/exceptions.rb +19 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +20 -16
- data/lib/action_controller/metal/helpers.rb +64 -67
- data/lib/action_controller/metal/http_authentication.rb +212 -199
- data/lib/action_controller/metal/implicit_render.rb +21 -17
- data/lib/action_controller/metal/instrumentation.rb +22 -12
- data/lib/action_controller/metal/live.rb +125 -92
- 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 +58 -58
- data/lib/action_controller/metal/permissions_policy.rb +14 -13
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +110 -84
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -82
- data/lib/action_controller/metal/request_forgery_protection.rb +279 -161
- data/lib/action_controller/metal/rescue.rb +12 -8
- data/lib/action_controller/metal/streaming.rb +174 -132
- data/lib/action_controller/metal/strong_parameters.rb +598 -473
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +23 -14
- data/lib/action_controller/metal.rb +145 -61
- data/lib/action_controller/railtie.rb +25 -9
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +105 -66
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +157 -128
- data/lib/action_controller.rb +17 -3
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +28 -29
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +48 -45
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +23 -21
- data/lib/action_dispatch/http/mime_negotiation.rb +37 -48
- data/lib/action_dispatch/http/mime_type.rb +60 -30
- data/lib/action_dispatch/http/mime_types.rb +5 -1
- data/lib/action_dispatch/http/parameters.rb +12 -10
- data/lib/action_dispatch/http/permissions_policy.rb +32 -27
- data/lib/action_dispatch/http/rack_cache.rb +4 -0
- data/lib/action_dispatch/http/request.rb +132 -79
- data/lib/action_dispatch/http/response.rb +136 -103
- data/lib/action_dispatch/http/upload.rb +19 -15
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +19 -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 +18 -15
- data/lib/action_dispatch/journey/route.rb +12 -9
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +13 -10
- data/lib/action_dispatch/journey/routes.rb +6 -4
- 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 +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +7 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +4 -0
- data/lib/action_dispatch/middleware/cookies.rb +192 -194
- data/lib/action_dispatch/middleware/debug_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/debug_locks.rb +18 -13
- data/lib/action_dispatch/middleware/debug_view.rb +9 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
- data/lib/action_dispatch/middleware/executor.rb +9 -1
- data/lib/action_dispatch/middleware/flash.rb +65 -46
- data/lib/action_dispatch/middleware/host_authorization.rb +22 -17
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -8
- data/lib/action_dispatch/middleware/reloader.rb +9 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +88 -83
- data/lib/action_dispatch/middleware/request_id.rb +15 -8
- data/lib/action_dispatch/middleware/server_timing.rb +8 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +7 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -7
- data/lib/action_dispatch/middleware/session/cookie_store.rb +32 -25
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +42 -28
- data/lib/action_dispatch/middleware/ssl.rb +60 -45
- data/lib/action_dispatch/middleware/stack.rb +15 -9
- data/lib/action_dispatch/middleware/static.rb +40 -34
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +47 -38
- data/lib/action_dispatch/railtie.rb +12 -4
- data/lib/action_dispatch/request/session.rb +39 -27
- data/lib/action_dispatch/request/utils.rb +10 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +59 -9
- data/lib/action_dispatch/routing/mapper.rb +686 -639
- data/lib/action_dispatch/routing/polymorphic_routes.rb +70 -61
- data/lib/action_dispatch/routing/redirection.rb +52 -38
- data/lib/action_dispatch/routing/route_set.rb +106 -62
- data/lib/action_dispatch/routing/routes_proxy.rb +16 -19
- data/lib/action_dispatch/routing/url_for.rb +131 -122
- data/lib/action_dispatch/routing.rb +152 -150
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +27 -19
- data/lib/action_dispatch/system_testing/driver.rb +16 -22
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +53 -31
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +36 -26
- data/lib/action_dispatch/testing/assertions/routing.rb +203 -95
- data/lib/action_dispatch/testing/assertions.rb +5 -1
- data/lib/action_dispatch/testing/integration.rb +240 -229
- data/lib/action_dispatch/testing/request_encoder.rb +6 -1
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +14 -9
- data/lib/action_dispatch/testing/test_request.rb +4 -2
- data/lib/action_dispatch/testing/test_response.rb +34 -19
- data/lib/action_dispatch.rb +52 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +18 -17
- metadata +86 -27
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -16,11 +16,11 @@ It consists of several modules:
|
|
16
16
|
subclassed to implement filters and actions to handle requests. The result
|
17
17
|
of an action is typically content generated from views.
|
18
18
|
|
19
|
-
With the Ruby on Rails framework, users only directly interface with the
|
19
|
+
With the Ruby on \Rails framework, users only directly interface with the
|
20
20
|
Action Controller module. Necessary Action Dispatch functionality is activated
|
21
21
|
by default and Action View rendering is implicitly triggered by Action
|
22
22
|
Controller. However, these modules are designed to function on their own and
|
23
|
-
can be used outside of Rails.
|
23
|
+
can be used outside of \Rails.
|
24
24
|
|
25
25
|
You can read more about Action Pack in the {Action Controller Overview}[https://guides.rubyonrails.org/action_controller_overview.html] guide.
|
26
26
|
|
@@ -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,10 +28,12 @@ module AbstractController
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
31
|
+
# # Abstract Controller Base
|
32
|
+
#
|
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.
|
33
37
|
class Base
|
34
38
|
##
|
35
39
|
# Returns the body of the HTTP response sent by the controller.
|
@@ -50,74 +54,76 @@ module AbstractController
|
|
50
54
|
attr_reader :abstract
|
51
55
|
alias_method :abstract?, :abstract
|
52
56
|
|
53
|
-
# Define a controller as abstract. See internal_methods for more
|
54
|
-
# details.
|
57
|
+
# Define a controller as abstract. See internal_methods for more details.
|
55
58
|
def abstract!
|
56
59
|
@abstract = true
|
57
60
|
end
|
58
61
|
|
59
62
|
def inherited(klass) # :nodoc:
|
60
|
-
# Define the abstract ivar on subclasses so that we don't get
|
61
|
-
#
|
63
|
+
# Define the abstract ivar on subclasses so that we don't get uninitialized ivar
|
64
|
+
# warnings
|
62
65
|
unless klass.instance_variable_defined?(:@abstract)
|
63
66
|
klass.instance_variable_set(:@abstract, false)
|
64
67
|
end
|
65
68
|
super
|
66
69
|
end
|
67
70
|
|
68
|
-
# A list of all internal methods for a controller. This finds the first
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
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)
|
74
77
|
def internal_methods
|
75
78
|
controller = self
|
79
|
+
methods = []
|
80
|
+
|
81
|
+
until controller.abstract?
|
82
|
+
methods += controller.public_instance_methods(false)
|
83
|
+
controller = controller.superclass
|
84
|
+
end
|
76
85
|
|
77
|
-
controller
|
78
|
-
controller.public_instance_methods(true)
|
86
|
+
controller.public_instance_methods(true) - methods
|
79
87
|
end
|
80
88
|
|
81
|
-
# A list of method names that should be considered actions. This
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
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.
|
86
96
|
#
|
87
|
-
# ==== Returns
|
88
|
-
# * <tt>Set</tt> - A set of all methods that should be considered actions.
|
89
97
|
def action_methods
|
90
98
|
@action_methods ||= begin
|
91
|
-
# All public instance methods of this class, including ancestors
|
92
|
-
methods
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
public_instance_methods(false))
|
97
|
-
|
99
|
+
# All public instance methods of this class, including ancestors except for
|
100
|
+
# public instance methods of Base and its ancestors.
|
101
|
+
methods = public_instance_methods(true) - internal_methods
|
102
|
+
# Be sure to include shadowed public instance methods of this class.
|
103
|
+
methods.concat(public_instance_methods(false))
|
98
104
|
methods.map!(&:to_s)
|
99
|
-
|
100
105
|
methods.to_set
|
101
106
|
end
|
102
107
|
end
|
103
108
|
|
104
|
-
# action_methods are cached and there is sometimes a need to refresh
|
105
|
-
#
|
106
|
-
#
|
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.
|
107
112
|
def clear_action_methods!
|
108
113
|
@action_methods = nil
|
109
114
|
end
|
110
115
|
|
111
116
|
# Returns the full controller name, underscored, without the ending Controller.
|
112
117
|
#
|
113
|
-
#
|
118
|
+
# class MyApp::MyPostsController < AbstractController::Base
|
114
119
|
#
|
115
|
-
#
|
120
|
+
# end
|
116
121
|
#
|
117
|
-
#
|
122
|
+
# MyApp::MyPostsController.controller_path # => "my_app/my_posts"
|
123
|
+
#
|
124
|
+
# #### Returns
|
125
|
+
# * `String`
|
118
126
|
#
|
119
|
-
# ==== Returns
|
120
|
-
# * <tt>String</tt>
|
121
127
|
def controller_path
|
122
128
|
@controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
|
123
129
|
end
|
@@ -127,19 +133,25 @@ module AbstractController
|
|
127
133
|
super
|
128
134
|
clear_action_methods!
|
129
135
|
end
|
136
|
+
|
137
|
+
def eager_load! # :nodoc:
|
138
|
+
action_methods
|
139
|
+
nil
|
140
|
+
end
|
130
141
|
end
|
131
142
|
|
132
143
|
abstract!
|
133
144
|
|
134
|
-
# Calls the action going through the entire
|
145
|
+
# Calls the action going through the entire Action Dispatch stack.
|
146
|
+
#
|
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.
|
135
150
|
#
|
136
|
-
#
|
137
|
-
#
|
138
|
-
# AbstractController::ActionNotFound error is raised.
|
151
|
+
# #### Returns
|
152
|
+
# * `self`
|
139
153
|
#
|
140
|
-
|
141
|
-
# * <tt>self</tt>
|
142
|
-
def process(action, *args)
|
154
|
+
def process(action, ...)
|
143
155
|
@_action_name = action.to_s
|
144
156
|
|
145
157
|
unless action_name = _find_action_name(@_action_name)
|
@@ -148,9 +160,8 @@ module AbstractController
|
|
148
160
|
|
149
161
|
@_response_body = nil
|
150
162
|
|
151
|
-
process_action(action_name,
|
163
|
+
process_action(action_name, ...)
|
152
164
|
end
|
153
|
-
ruby2_keywords(:process)
|
154
165
|
|
155
166
|
# Delegates to the class's ::controller_path.
|
156
167
|
def controller_path
|
@@ -162,31 +173,30 @@ module AbstractController
|
|
162
173
|
self.class.action_methods
|
163
174
|
end
|
164
175
|
|
165
|
-
# Returns true if a method for the action is available and
|
166
|
-
#
|
176
|
+
# Returns true if a method for the action is available and can be dispatched,
|
177
|
+
# false otherwise.
|
167
178
|
#
|
168
|
-
# Notice that
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
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.
|
183
|
+
#
|
184
|
+
# #### Parameters
|
185
|
+
# * `action_name` - The name of an action to be tested
|
172
186
|
#
|
173
|
-
# ==== Parameters
|
174
|
-
# * <tt>action_name</tt> - The name of an action to be tested
|
175
187
|
def available_action?(action_name)
|
176
188
|
_find_action_name(action_name)
|
177
189
|
end
|
178
190
|
|
179
|
-
# Tests if a response body is set. Used to determine if the
|
180
|
-
#
|
181
|
-
# 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.
|
182
193
|
def performed?
|
183
194
|
response_body
|
184
195
|
end
|
185
196
|
|
186
|
-
# Returns true if the given controller is capable of rendering
|
187
|
-
#
|
188
|
-
#
|
189
|
-
# 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.
|
190
200
|
def self.supports_path?
|
191
201
|
true
|
192
202
|
end
|
@@ -196,80 +206,83 @@ module AbstractController
|
|
196
206
|
end
|
197
207
|
|
198
208
|
private
|
199
|
-
# Returns true if the name can be considered an action because
|
200
|
-
#
|
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
|
201
214
|
#
|
202
|
-
# ==== Parameters
|
203
|
-
# * <tt>name</tt> - The name of an action to be tested
|
204
215
|
def action_method?(name)
|
205
216
|
self.class.action_methods.include?(name)
|
206
217
|
end
|
207
218
|
|
208
|
-
# Call the action. Override this in a subclass to modify the
|
209
|
-
#
|
210
|
-
#
|
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.
|
211
222
|
#
|
212
|
-
# Notice that the first argument is the method to be dispatched
|
213
|
-
#
|
223
|
+
# Notice that the first argument is the method to be dispatched which is **not**
|
224
|
+
# necessarily the same as the action name.
|
214
225
|
def process_action(...)
|
215
226
|
send_action(...)
|
216
227
|
end
|
217
228
|
|
218
|
-
# Actually call the method associated with the action. Override
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
# 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.
|
223
233
|
alias send_action send
|
224
234
|
|
225
|
-
# If the action name was not found, but a method called "action_missing"
|
226
|
-
#
|
227
|
-
#
|
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.
|
228
238
|
def _handle_action_missing(*args)
|
229
239
|
action_missing(@_action_name, *args)
|
230
240
|
end
|
231
241
|
|
232
|
-
# Takes an action name and returns the name of the method that will
|
233
|
-
#
|
242
|
+
# Takes an action name and returns the name of the method that will handle the
|
243
|
+
# action.
|
234
244
|
#
|
235
245
|
# It checks if the action name is valid and returns false otherwise.
|
236
246
|
#
|
237
247
|
# See method_for_action for more information.
|
238
248
|
#
|
239
|
-
#
|
240
|
-
# *
|
249
|
+
# #### Parameters
|
250
|
+
# * `action_name` - An action name to find a method name for
|
241
251
|
#
|
242
|
-
#
|
243
|
-
#
|
244
|
-
# *
|
245
|
-
#
|
252
|
+
#
|
253
|
+
# #### Returns
|
254
|
+
# * `string` - The name of the method that handles the action
|
255
|
+
# * false - No valid method name could be found.
|
256
|
+
#
|
257
|
+
# Raise `AbstractController::ActionNotFound`.
|
246
258
|
def _find_action_name(action_name)
|
247
259
|
_valid_action_name?(action_name) && method_for_action(action_name)
|
248
260
|
end
|
249
261
|
|
250
|
-
# Takes an action name and returns the name of the method that will
|
251
|
-
#
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
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.
|
255
274
|
#
|
256
|
-
#
|
257
|
-
#
|
258
|
-
# 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.
|
259
277
|
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
# the case.
|
278
|
+
# #### Parameters
|
279
|
+
# * `action_name` - An action name to find a method name for
|
263
280
|
#
|
264
|
-
# If none of these conditions are true, and +method_for_action+
|
265
|
-
# returns +nil+, an +AbstractController::ActionNotFound+ exception will be raised.
|
266
281
|
#
|
267
|
-
#
|
268
|
-
# *
|
282
|
+
# #### Returns
|
283
|
+
# * `string` - The name of the method that handles the action
|
284
|
+
# * `nil` - No method name could be found.
|
269
285
|
#
|
270
|
-
# ==== Returns
|
271
|
-
# * <tt>string</tt> - The name of the method that handles the action
|
272
|
-
# * <tt>nil</tt> - No method name could be found.
|
273
286
|
def method_for_action(action_name)
|
274
287
|
if action_method?(action_name)
|
275
288
|
action_name
|
@@ -1,20 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module AbstractController
|
4
6
|
module Caching
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
7
|
+
# # Abstract Controller Caching Fragments
|
8
|
+
#
|
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
|
11
14
|
# ActionView::Helpers::CacheHelper for more information.
|
12
15
|
#
|
13
|
-
# While it's strongly recommended that you use key-based cache
|
14
|
-
#
|
15
|
-
#
|
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:
|
16
19
|
#
|
17
|
-
#
|
20
|
+
# expire_fragment('name_of_cache')
|
18
21
|
module Fragments
|
19
22
|
extend ActiveSupport::Concern
|
20
23
|
|
@@ -33,38 +36,35 @@ module AbstractController
|
|
33
36
|
end
|
34
37
|
|
35
38
|
module ClassMethods
|
36
|
-
# Allows you to specify controller-wide key prefixes for
|
37
|
-
#
|
38
|
-
#
|
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.
|
39
42
|
#
|
40
|
-
# For example, you may want to prefix all fragment cache keys
|
41
|
-
#
|
42
|
-
# 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.
|
43
45
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
46
|
+
# class ApplicationController
|
47
|
+
# fragment_cache_key "v1"
|
48
|
+
# end
|
47
49
|
#
|
48
|
-
# When it's time to invalidate all fragments, simply change
|
49
|
-
#
|
50
|
-
# 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:
|
51
52
|
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
53
|
+
# class ApplicationController
|
54
|
+
# fragment_cache_key do
|
55
|
+
# @account.id.odd? ? "v1" : "v2"
|
56
|
+
# end
|
55
57
|
# end
|
56
|
-
# end
|
57
58
|
def fragment_cache_key(value = nil, &key)
|
58
59
|
self.fragment_cache_keys += [key || -> { value }]
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
62
|
-
# Given a key (as described in
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# 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.
|
68
68
|
def combined_fragment_cache_key(key)
|
69
69
|
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
70
70
|
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
@@ -75,8 +75,8 @@ module AbstractController
|
|
75
75
|
cache_key
|
76
76
|
end
|
77
77
|
|
78
|
-
# Writes
|
79
|
-
#
|
78
|
+
# Writes `content` to the location signified by `key` (see `expire_fragment` for
|
79
|
+
# acceptable formats).
|
80
80
|
def write_fragment(key, content, options = nil)
|
81
81
|
return content unless cache_configured?
|
82
82
|
|
@@ -88,8 +88,8 @@ module AbstractController
|
|
88
88
|
content
|
89
89
|
end
|
90
90
|
|
91
|
-
# Reads a cached fragment from the location signified by
|
92
|
-
#
|
91
|
+
# Reads a cached fragment from the location signified by `key` (see
|
92
|
+
# `expire_fragment` for acceptable formats).
|
93
93
|
def read_fragment(key, options = nil)
|
94
94
|
return unless cache_configured?
|
95
95
|
|
@@ -100,8 +100,8 @@ module AbstractController
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
# Check if a cached fragment from the location signified by
|
104
|
-
#
|
103
|
+
# Check if a cached fragment from the location signified by `key` exists (see
|
104
|
+
# `expire_fragment` for acceptable formats).
|
105
105
|
def fragment_exist?(key, options = nil)
|
106
106
|
return unless cache_configured?
|
107
107
|
key = combined_fragment_cache_key(key)
|
@@ -113,22 +113,21 @@ module AbstractController
|
|
113
113
|
|
114
114
|
# Removes fragments from the cache.
|
115
115
|
#
|
116
|
-
#
|
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).
|
117
127
|
#
|
118
|
-
# * String - This would normally take the form of a path, like
|
119
|
-
# <tt>pages/45/notes</tt>.
|
120
|
-
# * Hash - Treated as an implicit call to +url_for+, like
|
121
|
-
# <tt>{ controller: 'pages', action: 'notes', id: 45}</tt>
|
122
|
-
# * Regexp - Will remove any fragment that matches, so
|
123
|
-
# <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you
|
124
|
-
# don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because
|
125
|
-
# the actual filename matched looks like
|
126
|
-
# <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is
|
127
|
-
# only supported on caches that can iterate over all keys (unlike
|
128
|
-
# memcached).
|
129
128
|
#
|
130
|
-
#
|
131
|
-
#
|
129
|
+
# `options` is passed through to the cache store's `delete` method (or
|
130
|
+
# `delete_matched`, for Regexp keys).
|
132
131
|
def expire_fragment(key, options = nil)
|
133
132
|
return unless cache_configured?
|
134
133
|
key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
|