actionpack 4.2.10 → 7.2.0.rc1

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.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (202) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +86 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -14
  5. data/lib/abstract_controller/asset_paths.rb +5 -1
  6. data/lib/abstract_controller/base.rb +166 -136
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +126 -57
  10. data/lib/abstract_controller/collector.rb +13 -15
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +181 -132
  14. data/lib/abstract_controller/logger.rb +5 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
  16. data/lib/abstract_controller/rendering.rb +56 -56
  17. data/lib/abstract_controller/translation.rb +29 -15
  18. data/lib/abstract_controller/url_for.rb +15 -11
  19. data/lib/abstract_controller.rb +21 -5
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +154 -0
  22. data/lib/action_controller/base.rb +219 -155
  23. data/lib/action_controller/caching.rb +28 -68
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +35 -22
  27. data/lib/action_controller/metal/allow_browser.rb +119 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +259 -122
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +9 -5
  32. data/lib/action_controller/metal/data_streaming.rb +87 -104
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
  36. data/lib/action_controller/metal/exceptions.rb +71 -24
  37. data/lib/action_controller/metal/flash.rb +26 -19
  38. data/lib/action_controller/metal/head.rb +45 -36
  39. data/lib/action_controller/metal/helpers.rb +80 -64
  40. data/lib/action_controller/metal/http_authentication.rb +297 -244
  41. data/lib/action_controller/metal/implicit_render.rb +57 -9
  42. data/lib/action_controller/metal/instrumentation.rb +76 -64
  43. data/lib/action_controller/metal/live.rb +238 -176
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +177 -166
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +145 -118
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +203 -64
  51. data/lib/action_controller/metal/renderers.rb +108 -65
  52. data/lib/action_controller/metal/rendering.rb +216 -56
  53. data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
  54. data/lib/action_controller/metal/rescue.rb +19 -21
  55. data/lib/action_controller/metal/streaming.rb +179 -138
  56. data/lib/action_controller/metal/strong_parameters.rb +1058 -382
  57. data/lib/action_controller/metal/testing.rb +11 -17
  58. data/lib/action_controller/metal/url_for.rb +37 -21
  59. data/lib/action_controller/metal.rb +236 -138
  60. data/lib/action_controller/railtie.rb +89 -11
  61. data/lib/action_controller/railties/helpers.rb +5 -1
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +425 -497
  65. data/lib/action_controller.rb +44 -22
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +119 -63
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +364 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +36 -34
  72. data/lib/action_dispatch/http/filter_redirect.rb +24 -12
  73. data/lib/action_dispatch/http/headers.rb +66 -31
  74. data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
  75. data/lib/action_dispatch/http/mime_type.rb +196 -136
  76. data/lib/action_dispatch/http/mime_types.rb +25 -7
  77. data/lib/action_dispatch/http/parameters.rb +97 -45
  78. data/lib/action_dispatch/http/permissions_policy.rb +187 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +6 -0
  80. data/lib/action_dispatch/http/request.rb +299 -170
  81. data/lib/action_dispatch/http/response.rb +311 -160
  82. data/lib/action_dispatch/http/upload.rb +52 -23
  83. data/lib/action_dispatch/http/url.rb +201 -125
  84. data/lib/action_dispatch/journey/formatter.rb +110 -50
  85. data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
  88. data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
  89. data/lib/action_dispatch/journey/nodes/node.rb +100 -20
  90. data/lib/action_dispatch/journey/parser.rb +19 -17
  91. data/lib/action_dispatch/journey/parser.y +4 -3
  92. data/lib/action_dispatch/journey/parser_extras.rb +14 -4
  93. data/lib/action_dispatch/journey/path/pattern.rb +79 -63
  94. data/lib/action_dispatch/journey/route.rb +108 -44
  95. data/lib/action_dispatch/journey/router/utils.rb +41 -29
  96. data/lib/action_dispatch/journey/router.rb +64 -57
  97. data/lib/action_dispatch/journey/routes.rb +23 -21
  98. data/lib/action_dispatch/journey/scanner.rb +28 -17
  99. data/lib/action_dispatch/journey/visitors.rb +100 -54
  100. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  101. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  102. data/lib/action_dispatch/journey.rb +7 -5
  103. data/lib/action_dispatch/log_subscriber.rb +25 -0
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  106. data/lib/action_dispatch/middleware/callbacks.rb +7 -6
  107. data/lib/action_dispatch/middleware/cookies.rb +471 -328
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
  109. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  110. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
  112. data/lib/action_dispatch/middleware/executor.rb +32 -0
  113. data/lib/action_dispatch/middleware/flash.rb +143 -101
  114. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
  116. data/lib/action_dispatch/middleware/reloader.rb +10 -92
  117. data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
  118. data/lib/action_dispatch/middleware/request_id.rb +29 -15
  119. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
  125. data/lib/action_dispatch/middleware/ssl.rb +134 -36
  126. data/lib/action_dispatch/middleware/stack.rb +109 -44
  127. data/lib/action_dispatch/middleware/static.rb +159 -90
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
  132. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
  146. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
  147. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
  148. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  149. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  150. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  151. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
  152. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
  153. data/lib/action_dispatch/railtie.rb +44 -16
  154. data/lib/action_dispatch/request/session.rb +159 -69
  155. data/lib/action_dispatch/request/utils.rb +97 -23
  156. data/lib/action_dispatch/routing/endpoint.rb +11 -2
  157. data/lib/action_dispatch/routing/inspector.rb +195 -106
  158. data/lib/action_dispatch/routing/mapper.rb +1338 -955
  159. data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
  160. data/lib/action_dispatch/routing/redirection.rb +78 -51
  161. data/lib/action_dispatch/routing/route_set.rb +460 -374
  162. data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
  163. data/lib/action_dispatch/routing/url_for.rb +172 -124
  164. data/lib/action_dispatch/routing.rb +159 -158
  165. data/lib/action_dispatch/system_test_case.rb +206 -0
  166. data/lib/action_dispatch/system_testing/browser.rb +84 -0
  167. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  168. data/lib/action_dispatch/system_testing/server.rb +33 -0
  169. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  170. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  171. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  172. data/lib/action_dispatch/testing/assertions/response.rb +71 -39
  173. data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
  174. data/lib/action_dispatch/testing/assertions.rb +9 -6
  175. data/lib/action_dispatch/testing/integration.rb +486 -306
  176. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  177. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  178. data/lib/action_dispatch/testing/test_process.rb +35 -22
  179. data/lib/action_dispatch/testing/test_request.rb +29 -34
  180. data/lib/action_dispatch/testing/test_response.rb +48 -15
  181. data/lib/action_dispatch.rb +82 -40
  182. data/lib/action_pack/gem_version.rb +8 -4
  183. data/lib/action_pack/version.rb +6 -2
  184. data/lib/action_pack.rb +21 -18
  185. metadata +146 -56
  186. data/lib/action_controller/caching/fragments.rb +0 -103
  187. data/lib/action_controller/metal/force_ssl.rb +0 -97
  188. data/lib/action_controller/metal/hide_actions.rb +0 -40
  189. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  190. data/lib/action_controller/middleware.rb +0 -39
  191. data/lib/action_controller/model_naming.rb +0 -12
  192. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  193. data/lib/action_dispatch/journey/backwards.rb +0 -5
  194. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  195. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  196. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  197. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  199. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
  200. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  201. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  202. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2014 David Heinemeier Hansson
1
+ Copyright (c) David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  Action Pack is a framework for handling and responding to web requests. It
4
4
  provides mechanisms for *routing* (mapping request URLs to actions), defining
5
- *controllers* that implement actions, and generating responses by rendering
6
- *views*, which are templates of various formats. In short, Action Pack
7
- provides the view and controller layers in the MVC paradigm.
5
+ *controllers* that implement actions, and generating responses. In short, Action Pack
6
+ provides the controller layer in the MVC paradigm.
8
7
 
9
8
  It consists of several modules:
10
9
 
@@ -17,42 +16,42 @@ It consists of several modules:
17
16
  subclassed to implement filters and actions to handle requests. The result
18
17
  of an action is typically content generated from views.
19
18
 
20
- 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
21
20
  Action Controller module. Necessary Action Dispatch functionality is activated
22
21
  by default and Action View rendering is implicitly triggered by Action
23
22
  Controller. However, these modules are designed to function on their own and
24
- can be used outside of Rails.
23
+ can be used outside of \Rails.
25
24
 
25
+ You can read more about Action Pack in the {Action Controller Overview}[https://guides.rubyonrails.org/action_controller_overview.html] guide.
26
26
 
27
27
  == Download and installation
28
28
 
29
29
  The latest version of Action Pack can be installed with RubyGems:
30
30
 
31
- % [sudo] gem install actionpack
31
+ $ gem install actionpack
32
32
 
33
- Source code can be downloaded as part of the Rails project on GitHub
33
+ Source code can be downloaded as part of the \Rails project on GitHub:
34
34
 
35
- * https://github.com/rails/rails/tree/4-2-stable/actionpack
35
+ * https://github.com/rails/rails/tree/main/actionpack
36
36
 
37
37
 
38
38
  == License
39
39
 
40
40
  Action Pack is released under the MIT license:
41
41
 
42
- * http://www.opensource.org/licenses/MIT
42
+ * https://opensource.org/licenses/MIT
43
43
 
44
44
 
45
45
  == Support
46
46
 
47
- API documentation is at
47
+ API documentation is at:
48
48
 
49
- * http://api.rubyonrails.org
49
+ * https://api.rubyonrails.org
50
50
 
51
- Bug reports can be filed for the Ruby on Rails project here:
51
+ 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
55
  Feature requests should be discussed on the rails-core mailing list here:
56
56
 
57
- * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
58
-
57
+ * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
1
5
  module AbstractController
2
- module AssetPaths #:nodoc:
6
+ module AssetPaths # :nodoc:
3
7
  extend ActiveSupport::Concern
4
8
 
5
9
  included do
@@ -1,111 +1,131 @@
1
- require 'erubis'
2
- require 'set'
3
- require 'active_support/configurable'
4
- require 'active_support/descendants_tracker'
5
- require 'active_support/core_ext/module/anonymous'
1
+ # frozen_string_literal: true
6
2
 
7
- module AbstractController
8
- class Error < StandardError #:nodoc:
9
- end
3
+ # :markup: markdown
4
+
5
+ require "abstract_controller/error"
6
+ require "active_support/configurable"
7
+ require "active_support/descendants_tracker"
8
+ require "active_support/core_ext/module/anonymous"
9
+ require "active_support/core_ext/module/attr_internal"
10
10
 
11
+ module AbstractController
11
12
  # Raised when a non-existing controller action is triggered.
12
13
  class ActionNotFound < StandardError
14
+ attr_reader :controller, :action # :nodoc:
15
+
16
+ def initialize(message = nil, controller = nil, action = nil) # :nodoc:
17
+ @controller = controller
18
+ @action = action
19
+ super(message)
20
+ end
21
+
22
+ if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
23
+ include DidYouMean::Correctable # :nodoc:
24
+
25
+ def corrections # :nodoc:
26
+ @corrections ||= DidYouMean::SpellChecker.new(dictionary: controller.class.action_methods).correct(action)
27
+ end
28
+ end
13
29
  end
14
30
 
15
- # <tt>AbstractController::Base</tt> is a low-level API. Nobody should be
16
- # using it directly, and subclasses (like ActionController::Base) are
17
- # expected to provide their own +render+ method, since rendering means
18
- # different things depending on the context.
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.
19
37
  class Base
38
+ ##
39
+ # Returns the body of the HTTP response sent by the controller.
20
40
  attr_internal :response_body
41
+
42
+ ##
43
+ # Returns the name of the action this controller is processing.
21
44
  attr_internal :action_name
45
+
46
+ ##
47
+ # Returns the formats that can be processed by the controller.
22
48
  attr_internal :formats
23
49
 
24
50
  include ActiveSupport::Configurable
25
51
  extend ActiveSupport::DescendantsTracker
26
52
 
27
- undef_method :not_implemented
28
53
  class << self
29
54
  attr_reader :abstract
30
55
  alias_method :abstract?, :abstract
31
56
 
32
- # Define a controller as abstract. See internal_methods for more
33
- # details.
57
+ # Define a controller as abstract. See internal_methods for more details.
34
58
  def abstract!
35
59
  @abstract = true
36
60
  end
37
61
 
38
62
  def inherited(klass) # :nodoc:
39
- # Define the abstract ivar on subclasses so that we don't get
40
- # uninitialized ivar warnings
63
+ # Define the abstract ivar on subclasses so that we don't get uninitialized ivar
64
+ # warnings
41
65
  unless klass.instance_variable_defined?(:@abstract)
42
66
  klass.instance_variable_set(:@abstract, false)
43
67
  end
44
68
  super
45
69
  end
46
70
 
47
- # A list of all internal methods for a controller. This finds the first
48
- # abstract superclass of a controller, and gets a list of all public
49
- # instance methods on that abstract class. Public instance methods of
50
- # a controller would normally be considered action methods, so methods
51
- # declared on abstract classes are being removed.
52
- # (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)
53
77
  def internal_methods
54
78
  controller = self
79
+ methods = []
55
80
 
56
- controller = controller.superclass until controller.abstract?
57
- controller.public_instance_methods(true)
58
- end
81
+ until controller.abstract?
82
+ methods += controller.public_instance_methods(false)
83
+ controller = controller.superclass
84
+ end
59
85
 
60
- # The list of hidden actions. Defaults to an empty array.
61
- # This can be modified by other modules or subclasses
62
- # to specify particular actions as hidden.
63
- #
64
- # ==== Returns
65
- # * <tt>Array</tt> - An array of method names that should not be considered actions.
66
- def hidden_actions
67
- []
86
+ controller.public_instance_methods(true) - methods
68
87
  end
69
88
 
70
- # A list of method names that should be considered actions. This
71
- # includes all public instance methods on a controller, less
72
- # any internal methods (see #internal_methods), adding back in
73
- # any methods that are internal, but still exist on the class
74
- # itself. Finally, #hidden_actions are removed.
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.
75
96
  #
76
- # ==== Returns
77
- # * <tt>Set</tt> - A set of all methods that should be considered actions.
78
97
  def action_methods
79
98
  @action_methods ||= begin
80
- # All public instance methods of this class, including ancestors
81
- methods = (public_instance_methods(true) -
82
- # Except for public instance methods of Base and its ancestors
83
- internal_methods +
84
- # Be sure to include shadowed public instance methods of this class
85
- public_instance_methods(false)).uniq.map { |x| x.to_s } -
86
- # And always exclude explicitly hidden actions
87
- hidden_actions.to_a
88
-
89
- # Clear out AS callback method pollution
90
- Set.new(methods.reject { |method| method =~ /_one_time_conditions/ })
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))
104
+ methods.map!(&:to_s)
105
+ methods.to_set
91
106
  end
92
107
  end
93
108
 
94
- # action_methods are cached and there is sometimes need to refresh
95
- # them. clear_action_methods! allows you to do that, so next time
96
- # you run action_methods, they will be recalculated
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.
97
112
  def clear_action_methods!
98
113
  @action_methods = nil
99
114
  end
100
115
 
101
116
  # Returns the full controller name, underscored, without the ending Controller.
102
- # For instance, MyApp::MyPostsController would return "my_app/my_posts" for
103
- # controller_path.
104
117
  #
105
- # ==== Returns
106
- # * <tt>String</tt>
118
+ # class MyApp::MyPostsController < AbstractController::Base
119
+ #
120
+ # end
121
+ #
122
+ # MyApp::MyPostsController.controller_path # => "my_app/my_posts"
123
+ #
124
+ # #### Returns
125
+ # * `String`
126
+ #
107
127
  def controller_path
108
- @controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous?
128
+ @controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
109
129
  end
110
130
 
111
131
  # Refresh the cached action_methods when a new action_method is added.
@@ -113,146 +133,156 @@ module AbstractController
113
133
  super
114
134
  clear_action_methods!
115
135
  end
136
+
137
+ def eager_load! # :nodoc:
138
+ action_methods
139
+ nil
140
+ end
116
141
  end
117
142
 
118
143
  abstract!
119
144
 
120
- # Calls the action going through the entire action dispatch stack.
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.
121
150
  #
122
- # The actual method that is called is determined by calling
123
- # #method_for_action. If no method can handle the action, then an
124
- # AbstractController::ActionNotFound error is raised.
151
+ # #### Returns
152
+ # * `self`
125
153
  #
126
- # ==== Returns
127
- # * <tt>self</tt>
128
- def process(action, *args)
154
+ def process(action, ...)
129
155
  @_action_name = action.to_s
130
156
 
131
157
  unless action_name = _find_action_name(@_action_name)
132
- raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}"
158
+ raise ActionNotFound.new("The action '#{action}' could not be found for #{self.class.name}", self, action)
133
159
  end
134
160
 
135
161
  @_response_body = nil
136
162
 
137
- process_action(action_name, *args)
163
+ process_action(action_name, ...)
138
164
  end
139
165
 
140
- # Delegates to the class' #controller_path
166
+ # Delegates to the class's ::controller_path.
141
167
  def controller_path
142
168
  self.class.controller_path
143
169
  end
144
170
 
145
- # Delegates to the class' #action_methods
171
+ # Delegates to the class's ::action_methods.
146
172
  def action_methods
147
173
  self.class.action_methods
148
174
  end
149
175
 
150
- # Returns true if a method for the action is available and
151
- # can be dispatched, false otherwise.
176
+ # Returns true if a method for the action is available and can be dispatched,
177
+ # false otherwise.
152
178
  #
153
- # Notice that <tt>action_methods.include?("foo")</tt> may return
154
- # false and <tt>available_action?("foo")</tt> returns true because
155
- # this method considers actions that are also available
156
- # through other means, for example, implicit render ones.
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.
157
183
  #
158
- # ==== Parameters
159
- # * <tt>action_name</tt> - The name of an action to be tested
184
+ # #### Parameters
185
+ # * `action_name` - The name of an action to be tested
160
186
  #
161
- # ==== Returns
162
- # * <tt>TrueClass</tt>, <tt>FalseClass</tt>
163
187
  def available_action?(action_name)
164
- _find_action_name(action_name).present?
188
+ _find_action_name(action_name)
189
+ end
190
+
191
+ # Tests if a response body is set. Used to determine if the `process_action`
192
+ # callback needs to be terminated in AbstractController::Callbacks.
193
+ def performed?
194
+ response_body
165
195
  end
166
196
 
167
- # Returns true if the given controller is capable of rendering
168
- # a path. A subclass of +AbstractController::Base+
169
- # may return false. An Email controller for example does not
170
- # 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.
171
200
  def self.supports_path?
172
201
  true
173
202
  end
174
203
 
175
- private
204
+ def inspect # :nodoc:
205
+ "#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
206
+ end
176
207
 
177
- # Returns true if the name can be considered an action because
178
- # it has a method defined in the controller.
179
- #
180
- # ==== Parameters
181
- # * <tt>name</tt> - The name of an action to be tested
208
+ private
209
+ # Returns true if the name can be considered an action because it has a method
210
+ # defined in the controller.
182
211
  #
183
- # ==== Returns
184
- # * <tt>TrueClass</tt>, <tt>FalseClass</tt>
212
+ # #### Parameters
213
+ # * `name` - The name of an action to be tested
185
214
  #
186
- # :api: private
187
215
  def action_method?(name)
188
216
  self.class.action_methods.include?(name)
189
217
  end
190
218
 
191
- # Call the action. Override this in a subclass to modify the
192
- # behavior around processing an action. This, and not #process,
193
- # is the intended way to override action dispatching.
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.
194
222
  #
195
- # Notice that the first argument is the method to be dispatched
196
- # which is *not* necessarily the same as the action name.
197
- def process_action(method_name, *args)
198
- send_action(method_name, *args)
223
+ # Notice that the first argument is the method to be dispatched which is **not**
224
+ # necessarily the same as the action name.
225
+ def process_action(...)
226
+ send_action(...)
199
227
  end
200
228
 
201
- # Actually call the method associated with the action. Override
202
- # this method if you wish to change how action methods are called,
203
- # not to add additional behavior around it. For example, you would
204
- # override #send_action if you want to inject arguments into the
205
- # 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.
206
233
  alias send_action send
207
234
 
208
- # If the action name was not found, but a method called "action_missing"
209
- # was found, #method_for_action will return "_handle_action_missing".
210
- # This method calls #action_missing with the current action name.
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.
211
238
  def _handle_action_missing(*args)
212
239
  action_missing(@_action_name, *args)
213
240
  end
214
241
 
215
- # Takes an action name and returns the name of the method that will
216
- # handle the action.
242
+ # Takes an action name and returns the name of the method that will handle the
243
+ # action.
217
244
  #
218
245
  # It checks if the action name is valid and returns false otherwise.
219
246
  #
220
247
  # See method_for_action for more information.
221
248
  #
222
- # ==== Parameters
223
- # * <tt>action_name</tt> - An action name to find a method name for
249
+ # #### Parameters
250
+ # * `action_name` - An action name to find a method name for
224
251
  #
225
- # ==== Returns
226
- # * <tt>string</tt> - The name of the method that handles the action
227
- # * false - No valid method name could be found.
228
- # Raise AbstractController::ActionNotFound.
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`.
229
258
  def _find_action_name(action_name)
230
259
  _valid_action_name?(action_name) && method_for_action(action_name)
231
260
  end
232
261
 
233
- # Takes an action name and returns the name of the method that will
234
- # handle the action. In normal cases, this method returns the same
235
- # name as it receives. By default, if #method_for_action receives
236
- # a name that is not an action, it will look for an #action_missing
237
- # method and return "_handle_action_missing" if one is found.
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.
238
274
  #
239
- # Subclasses may override this method to add additional conditions
240
- # that should be considered an action. For instance, an HTTP controller
241
- # 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.
242
277
  #
243
- # If you override this method to handle additional cases, you may
244
- # also provide a method (like _handle_method_missing) to handle
245
- # the case.
278
+ # #### Parameters
279
+ # * `action_name` - An action name to find a method name for
246
280
  #
247
- # If none of these conditions are true, and method_for_action
248
- # returns nil, an AbstractController::ActionNotFound exception will be raised.
249
281
  #
250
- # ==== Parameters
251
- # * <tt>action_name</tt> - An action name to find a method name for
282
+ # #### Returns
283
+ # * `string` - The name of the method that handles the action
284
+ # * `nil` - No method name could be found.
252
285
  #
253
- # ==== Returns
254
- # * <tt>string</tt> - The name of the method that handles the action
255
- # * <tt>nil</tt> - No method name could be found.
256
286
  def method_for_action(action_name)
257
287
  if action_method?(action_name)
258
288
  action_name
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module AbstractController
6
+ module Caching
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
14
+ # ActionView::Helpers::CacheHelper for more information.
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:
19
+ #
20
+ # expire_fragment('name_of_cache')
21
+ module Fragments
22
+ extend ActiveSupport::Concern
23
+
24
+ included do
25
+ if respond_to?(:class_attribute)
26
+ class_attribute :fragment_cache_keys
27
+ else
28
+ mattr_writer :fragment_cache_keys
29
+ end
30
+
31
+ self.fragment_cache_keys = []
32
+
33
+ if respond_to?(:helper_method)
34
+ helper_method :combined_fragment_cache_key
35
+ end
36
+ end
37
+
38
+ module ClassMethods
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.
42
+ #
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
+ #
46
+ # class ApplicationController
47
+ # fragment_cache_key "v1"
48
+ # end
49
+ #
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:
52
+ #
53
+ # class ApplicationController
54
+ # fragment_cache_key do
55
+ # @account.id.odd? ? "v1" : "v2"
56
+ # end
57
+ # end
58
+ def fragment_cache_key(value = nil, &key)
59
+ self.fragment_cache_keys += [key || -> { value }]
60
+ end
61
+ end
62
+
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
+ def combined_fragment_cache_key(key)
69
+ head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
70
+ tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
71
+
72
+ cache_key = [:views, ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"], head, tail]
73
+ cache_key.flatten!(1)
74
+ cache_key.compact!
75
+ cache_key
76
+ end
77
+
78
+ # Writes `content` to the location signified by `key` (see `expire_fragment` for
79
+ # acceptable formats).
80
+ def write_fragment(key, content, options = nil)
81
+ return content unless cache_configured?
82
+
83
+ key = combined_fragment_cache_key(key)
84
+ instrument_fragment_cache :write_fragment, key do
85
+ content = content.to_str
86
+ cache_store.write(key, content, options)
87
+ end
88
+ content
89
+ end
90
+
91
+ # Reads a cached fragment from the location signified by `key` (see
92
+ # `expire_fragment` for acceptable formats).
93
+ def read_fragment(key, options = nil)
94
+ return unless cache_configured?
95
+
96
+ key = combined_fragment_cache_key(key)
97
+ instrument_fragment_cache :read_fragment, key do
98
+ result = cache_store.read(key, options)
99
+ result.respond_to?(:html_safe) ? result.html_safe : result
100
+ end
101
+ end
102
+
103
+ # Check if a cached fragment from the location signified by `key` exists (see
104
+ # `expire_fragment` for acceptable formats).
105
+ def fragment_exist?(key, options = nil)
106
+ return unless cache_configured?
107
+ key = combined_fragment_cache_key(key)
108
+
109
+ instrument_fragment_cache :exist_fragment?, key do
110
+ cache_store.exist?(key, options)
111
+ end
112
+ end
113
+
114
+ # Removes fragments from the cache.
115
+ #
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).
127
+ #
128
+ #
129
+ # `options` is passed through to the cache store's `delete` method (or
130
+ # `delete_matched`, for Regexp keys).
131
+ def expire_fragment(key, options = nil)
132
+ return unless cache_configured?
133
+ key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
134
+
135
+ instrument_fragment_cache :expire_fragment, key do
136
+ if key.is_a?(Regexp)
137
+ cache_store.delete_matched(key, options)
138
+ else
139
+ cache_store.delete(key, options)
140
+ end
141
+ end
142
+ end
143
+
144
+ def instrument_fragment_cache(name, key, &block) # :nodoc:
145
+ ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", instrument_payload(key), &block)
146
+ end
147
+ end
148
+ end
149
+ end