actionpack 7.1.5.1 → 8.1.2

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