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
@@ -1,119 +1,209 @@
1
- require 'active_support/dependencies'
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/dependencies"
6
+ require "active_support/core_ext/name_error"
2
7
 
3
8
  module AbstractController
4
9
  module Helpers
5
10
  extend ActiveSupport::Concern
6
11
 
7
12
  included do
8
- class_attribute :_helpers
9
- self._helpers = Module.new
13
+ class_attribute :_helper_methods, default: Array.new
10
14
 
11
- class_attribute :_helper_methods
12
- self._helper_methods = Array.new
15
+ # This is here so that it is always higher in the inheritance chain than the
16
+ # definition in lib/action_view/rendering.rb
17
+ redefine_singleton_method(:_helpers) do
18
+ if @_helpers ||= nil
19
+ @_helpers
20
+ else
21
+ superclass._helpers
22
+ end
23
+ end
24
+
25
+ self._helpers = define_helpers_module(self)
13
26
  end
14
27
 
15
- class MissingHelperError < LoadError
16
- def initialize(error, path)
17
- @error = error
18
- @path = "helpers/#{path}.rb"
19
- set_backtrace error.backtrace
28
+ def _helpers
29
+ self.class._helpers
30
+ end
20
31
 
21
- if error.path =~ /^#{path}(\.rb)?$/
22
- super("Missing helper file helpers/%s.rb" % path)
23
- else
24
- raise error
32
+ module Resolution # :nodoc:
33
+ def modules_for_helpers(modules_or_helper_prefixes)
34
+ modules_or_helper_prefixes.flatten.map! do |module_or_helper_prefix|
35
+ case module_or_helper_prefix
36
+ when Module
37
+ module_or_helper_prefix
38
+ when String, Symbol
39
+ helper_prefix = module_or_helper_prefix.to_s
40
+ helper_prefix = helper_prefix.camelize unless helper_prefix.start_with?(/[A-Z]/)
41
+ "#{helper_prefix}Helper".constantize
42
+ else
43
+ raise ArgumentError, "helper must be a String, Symbol, or Module"
44
+ end
45
+ end
46
+ end
47
+
48
+ def all_helpers_from_path(path)
49
+ helpers = Array(path).flat_map do |_path|
50
+ names = Dir["#{_path}/**/*_helper.rb"].map { |file| file[_path.to_s.size + 1..-"_helper.rb".size - 1] }
51
+ names.sort!
25
52
  end
53
+ helpers.uniq!
54
+ helpers
55
+ end
56
+
57
+ def helper_modules_from_paths(paths)
58
+ modules_for_helpers(all_helpers_from_path(paths))
26
59
  end
27
60
  end
28
61
 
62
+ extend Resolution
63
+
29
64
  module ClassMethods
30
- # When a class is inherited, wrap its helper module in a new module.
31
- # This ensures that the parent class's module can be changed
32
- # independently of the child class's.
65
+ # When a class is inherited, wrap its helper module in a new module. This
66
+ # ensures that the parent class's module can be changed independently of the
67
+ # child class's.
33
68
  def inherited(klass)
34
- helpers = _helpers
35
- klass._helpers = Module.new { include helpers }
69
+ # Inherited from parent by default
70
+ klass._helpers = nil
71
+
36
72
  klass.class_eval { default_helper_module! } unless klass.anonymous?
37
73
  super
38
74
  end
39
75
 
40
- # Declare a controller method as a helper. For example, the following
41
- # makes the +current_user+ controller method available to the view:
42
- # class ApplicationController < ActionController::Base
43
- # helper_method :current_user, :logged_in?
76
+ attr_writer :_helpers
77
+
78
+ include Resolution
79
+
80
+ ##
81
+ # :method: modules_for_helpers
82
+ # :call-seq: modules_for_helpers(modules_or_helper_prefixes)
44
83
  #
45
- # def current_user
46
- # @current_user ||= User.find_by(id: session[:user])
47
- # end
84
+ # Given an array of values like the ones accepted by `helper`, this method
85
+ # returns an array with the corresponding modules, in the same order.
86
+ #
87
+ # ActionController::Base.modules_for_helpers(["application", "chart", "rubygems"])
88
+ # # => [ApplicationHelper, ChartHelper, RubygemsHelper]
89
+ #
90
+ #--
91
+ # Implemented by Resolution#modules_for_helpers.
92
+
93
+ # :method: # all_helpers_from_path
94
+ # :call-seq: all_helpers_from_path(path)
95
+ #
96
+ # Returns a list of helper names in a given path.
48
97
  #
49
- # def logged_in?
50
- # current_user != nil
98
+ # ActionController::Base.all_helpers_from_path 'app/helpers'
99
+ # # => ["application", "chart", "rubygems"]
100
+ #
101
+ #--
102
+ # Implemented by Resolution#all_helpers_from_path.
103
+
104
+ # Declare a controller method as a helper. For example, the following
105
+ # makes the `current_user` and `logged_in?` controller methods available
106
+ # to the view:
107
+ # class ApplicationController < ActionController::Base
108
+ # helper_method :current_user, :logged_in?
109
+ #
110
+ # private
111
+ # def current_user
112
+ # @current_user ||= User.find_by(id: session[:user])
113
+ # end
114
+ #
115
+ # def logged_in?
116
+ # current_user != nil
117
+ # end
51
118
  # end
52
- # end
53
119
  #
54
120
  # In a view:
55
- # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
56
- #
57
- # ==== Parameters
58
- # * <tt>method[, method]</tt> - A name or names of a method on the controller
59
- # to be made available on the view.
60
- def helper_method(*meths)
61
- meths.flatten!
62
- self._helper_methods += meths
63
-
64
- meths.each do |meth|
65
- _helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
66
- def #{meth}(*args, &blk) # def current_user(*args, &blk)
67
- controller.send(%(#{meth}), *args, &blk) # controller.send(:current_user, *args, &blk)
68
- end # end
121
+ # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
122
+ #
123
+ # #### Parameters
124
+ # * `method[, method]` - A name or names of a method on the controller to be
125
+ # made available on the view.
126
+ def helper_method(*methods)
127
+ methods.flatten!
128
+ self._helper_methods += methods
129
+
130
+ location = caller_locations(1, 1).first
131
+ file, line = location.path, location.lineno
132
+
133
+ methods.each do |method|
134
+ # def current_user(...)
135
+ # controller.send(:'current_user', ...)
136
+ # end
137
+ _helpers_for_modification.class_eval <<~ruby_eval.lines.map(&:strip).join(";"), file, line
138
+ def #{method}(...)
139
+ controller.send(:'#{method}', ...)
140
+ end
69
141
  ruby_eval
70
142
  end
71
143
  end
72
144
 
73
- # The +helper+ class method can take a series of helper module names, a block, or both.
145
+ # Includes the given modules in the template class.
146
+ #
147
+ # Modules can be specified in different ways. All of the following calls include
148
+ # `FooHelper`:
149
+ #
150
+ # # Module, recommended.
151
+ # helper FooHelper
152
+ #
153
+ # # String/symbol without the "helper" suffix, camel or snake case.
154
+ # helper "Foo"
155
+ # helper :Foo
156
+ # helper "foo"
157
+ # helper :foo
74
158
  #
75
- # ==== Options
76
- # * <tt>*args</tt> - Module, Symbol, String
77
- # * <tt>block</tt> - A block defining helper methods
159
+ # The last two assume that `"foo".camelize` returns "Foo".
78
160
  #
79
- # When the argument is a module it will be included directly in the template class.
80
- # helper FooHelper # => includes FooHelper
161
+ # When strings or symbols are passed, the method finds the actual module object
162
+ # using String#constantize. Therefore, if the module has not been yet loaded, it
163
+ # has to be autoloadable, which is normally the case.
81
164
  #
82
- # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
83
- # and include the module in the template class. The second form illustrates how to include custom helpers
84
- # when working with namespaced controllers, or other cases where the file containing the helper definition is not
85
- # in one of Rails' standard load paths:
86
- # helper :foo # => requires 'foo_helper' and includes FooHelper
87
- # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
165
+ # Namespaces are supported. The following calls include `Foo::BarHelper`:
88
166
  #
89
- # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
90
- # to the template.
167
+ # # Module, recommended.
168
+ # helper Foo::BarHelper
91
169
  #
92
- # # One line
93
- # helper { def hello() "Hello, world!" end }
170
+ # # String/symbol without the "helper" suffix, camel or snake case.
171
+ # helper "Foo::Bar"
172
+ # helper :"Foo::Bar"
173
+ # helper "foo/bar"
174
+ # helper :"foo/bar"
94
175
  #
95
- # # Multi-line
96
- # helper do
97
- # def foo(bar)
98
- # "#{bar} is the very best"
176
+ # The last two assume that `"foo/bar".camelize` returns "Foo::Bar".
177
+ #
178
+ # The method accepts a block too. If present, the block is evaluated in the
179
+ # context of the controller helper module. This simple call makes the `wadus`
180
+ # method available in templates of the enclosing controller:
181
+ #
182
+ # helper do
183
+ # def wadus
184
+ # "wadus"
185
+ # end
99
186
  # end
100
- # end
101
187
  #
102
- # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
103
- # +symbols+, +strings+, +modules+ and blocks.
188
+ # Furthermore, all the above styles can be mixed together:
104
189
  #
105
- # helper(:three, BlindHelper) { def mice() 'mice' end }
190
+ # helper FooHelper, "woo", "bar/baz" do
191
+ # def wadus
192
+ # "wadus"
193
+ # end
194
+ # end
106
195
  #
107
196
  def helper(*args, &block)
108
197
  modules_for_helpers(args).each do |mod|
109
- add_template_helper(mod)
198
+ next if _helpers.include?(mod)
199
+ _helpers_for_modification.include(mod)
110
200
  end
111
201
 
112
- _helpers.module_eval(&block) if block_given?
202
+ _helpers_for_modification.module_eval(&block) if block_given?
113
203
  end
114
204
 
115
- # Clears up all existing helpers in this class, only keeping the helper
116
- # with the same name as this class.
205
+ # Clears up all existing helpers in this class, only keeping the helper with the
206
+ # same name as this class.
117
207
  def clear_helpers
118
208
  inherited_helper_methods = _helper_methods
119
209
  self._helpers = Module.new
@@ -123,72 +213,31 @@ module AbstractController
123
213
  default_helper_module! unless anonymous?
124
214
  end
125
215
 
126
- # Returns a list of modules, normalized from the acceptable kinds of
127
- # helpers with the following behavior:
128
- #
129
- # String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper",
130
- # and "foo_bar_helper.rb" is loaded using require_dependency.
131
- #
132
- # Module:: No further processing
133
- #
134
- # After loading the appropriate files, the corresponding modules
135
- # are returned.
136
- #
137
- # ==== Parameters
138
- # * <tt>args</tt> - An array of helpers
139
- #
140
- # ==== Returns
141
- # * <tt>Array</tt> - A normalized list of modules for the list of
142
- # helpers provided.
143
- def modules_for_helpers(args)
144
- args.flatten.map! do |arg|
145
- case arg
146
- when String, Symbol
147
- file_name = "#{arg.to_s.underscore}_helper"
148
- begin
149
- require_dependency(file_name)
150
- rescue LoadError => e
151
- raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
152
- end
153
-
154
- mod_name = file_name.camelize
155
- begin
156
- mod_name.constantize
157
- rescue LoadError
158
- # dependencies.rb gives a similar error message but its wording is
159
- # not as clear because it mentions autoloading. To the user all it
160
- # matters is that a helper module couldn't be loaded, autoloading
161
- # is an internal mechanism that should not leak.
162
- raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
163
- end
164
- when Module
165
- arg
166
- else
167
- raise ArgumentError, "helper must be a String, Symbol, or Module"
168
- end
216
+ def _helpers_for_modification
217
+ unless @_helpers
218
+ self._helpers = define_helpers_module(self, superclass._helpers)
169
219
  end
220
+ _helpers
170
221
  end
171
222
 
172
223
  private
173
- # Makes all the (instance) methods in the helper module available to templates
174
- # rendered through this controller.
175
- #
176
- # ==== Parameters
177
- # * <tt>module</tt> - The module to include into the current helper module
178
- # for the class
179
- def add_template_helper(mod)
180
- _helpers.module_eval { include mod }
181
- end
224
+ def define_helpers_module(klass, helpers = nil)
225
+ # In some tests inherited is called explicitly. In that case, just return the
226
+ # module from the first time it was defined
227
+ return klass.const_get(:HelperMethods) if klass.const_defined?(:HelperMethods, false)
228
+
229
+ mod = Module.new
230
+ klass.const_set(:HelperMethods, mod)
231
+ mod.include(helpers) if helpers
232
+ mod
233
+ end
182
234
 
183
- def default_helper_module!
184
- module_name = name.sub(/Controller$/, '')
185
- module_path = module_name.underscore
186
- helper module_path
187
- rescue MissingSourceFile => e
188
- raise e unless e.is_missing? "helpers/#{module_path}_helper"
189
- rescue NameError => e
190
- raise e unless e.missing_name? "#{module_name}Helper"
191
- end
235
+ def default_helper_module!
236
+ helper_prefix = name.delete_suffix("Controller")
237
+ helper(helper_prefix)
238
+ rescue NameError => e
239
+ raise unless e.missing_name?("#{helper_prefix}Helper")
240
+ end
192
241
  end
193
242
  end
194
243
  end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
1
5
  require "active_support/benchmarkable"
2
6
 
3
7
  module AbstractController
4
- module Logger #:nodoc:
8
+ module Logger # :nodoc:
5
9
  extend ActiveSupport::Concern
6
10
 
7
11
  included do
@@ -1,3 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/core_ext/module/introspection"
6
+
1
7
  module AbstractController
2
8
  module Railties
3
9
  module RoutesHelpers
@@ -5,10 +11,11 @@ module AbstractController
5
11
  Module.new do
6
12
  define_method(:inherited) do |klass|
7
13
  super(klass)
8
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
9
- klass.send(:include, namespace.railtie_routes_url_helpers(include_path_helpers))
14
+
15
+ if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
16
+ klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
10
17
  else
11
- klass.send(:include, routes.url_helpers(include_path_helpers))
18
+ klass.include(routes.url_helpers(include_path_helpers))
12
19
  end
13
20
  end
14
21
  end
@@ -1,12 +1,15 @@
1
- require 'active_support/concern'
2
- require 'active_support/core_ext/class/attribute'
3
- require 'action_view'
4
- require 'action_view/view_paths'
5
- require 'set'
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "abstract_controller/error"
6
+ require "action_view"
7
+ require "action_view/view_paths"
8
+ require "set"
6
9
 
7
10
  module AbstractController
8
11
  class DoubleRenderError < Error
9
- DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
12
+ DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...); return\"."
10
13
 
11
14
  def initialize(message = nil)
12
15
  super(message || DEFAULT_MESSAGE)
@@ -17,66 +20,58 @@ module AbstractController
17
20
  extend ActiveSupport::Concern
18
21
  include ActionView::ViewPaths
19
22
 
20
- # Normalize arguments, options and then delegates render_to_body and
21
- # sticks the result in self.response_body.
22
- # :api: public
23
+ # Normalizes arguments and options, and then delegates to render_to_body and
24
+ # sticks the result in `self.response_body`.
25
+ #
26
+ # Supported options depend on the underlying `render_to_body` implementation.
23
27
  def render(*args, &block)
24
28
  options = _normalize_render(*args, &block)
25
- self.response_body = render_to_body(options)
26
- _process_format(rendered_format, options) if rendered_format
27
- self.response_body
29
+ rendered_body = render_to_body(options)
30
+ if options[:html]
31
+ _set_html_content_type
32
+ else
33
+ _set_rendered_content_type rendered_format
34
+ end
35
+ _set_vary_header
36
+ self.response_body = rendered_body
28
37
  end
29
38
 
30
- # Raw rendering of a template to a string.
31
- #
32
- # It is similar to render, except that it does not
33
- # set the response_body and it should be guaranteed
34
- # to always return a string.
39
+ # Similar to #render, but only returns the rendered template as a string,
40
+ # instead of setting `self.response_body`.
35
41
  #
36
- # If a component extends the semantics of response_body
37
- # (as Action Controller extends it to be anything that
38
- # responds to the method each), this method needs to be
39
- # overridden in order to still return a string.
40
- # :api: plugin
42
+ # If a component extends the semantics of `response_body` (as ActionController
43
+ # extends it to be anything that responds to the method each), this method needs
44
+ # to be overridden in order to still return a string.
41
45
  def render_to_string(*args, &block)
42
46
  options = _normalize_render(*args, &block)
43
47
  render_to_body(options)
44
48
  end
45
49
 
46
50
  # Performs the actual template rendering.
47
- # :api: public
48
51
  def render_to_body(options = {})
49
52
  end
50
53
 
51
- # Returns Content-Type of rendered content
52
- # :api: public
54
+ # Returns `Content-Type` of rendered content.
53
55
  def rendered_format
54
- Mime::TEXT
56
+ Mime[:text]
55
57
  end
56
58
 
57
- DEFAULT_PROTECTED_INSTANCE_VARIABLES = Set.new %w(
58
- @_action_name @_response_body @_formats @_prefixes @_config
59
- @_view_context_class @_view_renderer @_lookup_context
60
- @_routes @_db_runtime
61
- ).map(&:to_sym)
59
+ DEFAULT_PROTECTED_INSTANCE_VARIABLES = %i(@_action_name @_response_body @_formats @_prefixes)
62
60
 
63
- # This method should return a hash with assigns.
64
- # You can overwrite this configuration per controller.
65
- # :api: public
61
+ # This method should return a hash with assigns. You can overwrite this
62
+ # configuration per controller.
66
63
  def view_assigns
67
- protected_vars = _protected_ivars
68
- variables = instance_variables
64
+ variables = instance_variables - _protected_ivars
69
65
 
70
- variables.reject! { |s| protected_vars.include? s }
71
- variables.each_with_object({}) { |name, hash|
66
+ variables.each_with_object({}) do |name, hash|
72
67
  hash[name.slice(1, name.length)] = instance_variable_get(name)
73
- }
68
+ end
74
69
  end
75
70
 
76
- # Normalize args by converting render "foo" to render :action => "foo" and
77
- # render "foo/bar" to render :file => "foo/bar".
78
- # :api: plugin
79
- def _normalize_args(action=nil, options={})
71
+ private
72
+ # Normalize args by converting `render "foo"` to `render action: "foo"` and
73
+ # `render "foo/bar"` to `render file: "foo/bar"`.
74
+ def _normalize_args(action = nil, options = {}) # :doc:
80
75
  if action.respond_to?(:permitted?)
81
76
  if action.permitted?
82
77
  action
@@ -91,35 +86,40 @@ module AbstractController
91
86
  end
92
87
 
93
88
  # Normalize options.
94
- # :api: plugin
95
- def _normalize_options(options)
89
+ def _normalize_options(options) # :doc:
96
90
  options
97
91
  end
98
92
 
99
93
  # Process extra options.
100
- # :api: plugin
101
- def _process_options(options)
94
+ def _process_options(options) # :doc:
102
95
  options
103
96
  end
104
97
 
105
98
  # Process the rendered format.
106
- # :api: private
107
- def _process_format(format, options = {})
99
+ def _process_format(format) # :nodoc:
100
+ end
101
+
102
+ def _process_variant(options)
103
+ end
104
+
105
+ def _set_html_content_type # :nodoc:
106
+ end
107
+
108
+ def _set_vary_header # :nodoc:
109
+ end
110
+
111
+ def _set_rendered_content_type(format) # :nodoc:
108
112
  end
109
113
 
110
114
  # Normalize args and options.
111
- # :api: private
112
- def _normalize_render(*args, &block)
115
+ def _normalize_render(*args, &block) # :nodoc:
113
116
  options = _normalize_args(*args, &block)
114
- #TODO: remove defined? when we restore AP <=> AV dependency
115
- if defined?(request) && request && request.variant.present?
116
- options[:variant] = request.variant
117
- end
117
+ _process_variant(options)
118
118
  _normalize_options(options)
119
119
  options
120
120
  end
121
121
 
122
- def _protected_ivars # :nodoc:
122
+ def _protected_ivars
123
123
  DEFAULT_PROTECTED_INSTANCE_VARIABLES
124
124
  end
125
125
  end
@@ -1,27 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/html_safe_translation"
6
+
1
7
  module AbstractController
2
8
  module Translation
3
- # Delegates to <tt>I18n.translate</tt>. Also aliased as <tt>t</tt>.
9
+ # Delegates to `I18n.translate`.
4
10
  #
5
11
  # When the given key starts with a period, it will be scoped by the current
6
- # controller and action. So if you call <tt>translate(".foo")</tt> from
7
- # <tt>PeopleController#index</tt>, it will convert the call to
8
- # <tt>I18n.translate("people.index.foo")</tt>. This makes it less repetitive
9
- # to translate many keys within the same controller / action and gives you a
10
- # simple framework for scoping them consistently.
11
- def translate(*args)
12
- key = args.first
13
- if key.is_a?(String) && (key[0] == '.')
14
- key = "#{ controller_path.tr('/', '.') }.#{ action_name }#{ key }"
15
- args[0] = key
12
+ # controller and action. So if you call `translate(".foo")` from
13
+ # `PeopleController#index`, it will convert the call to
14
+ # `I18n.translate("people.index.foo")`. This makes it less repetitive to
15
+ # translate many keys within the same controller / action and gives you a simple
16
+ # framework for scoping them consistently.
17
+ def translate(key, **options)
18
+ if key&.start_with?(".")
19
+ path = controller_path.tr("/", ".")
20
+ defaults = [:"#{path}#{key}"]
21
+ defaults << options[:default] if options[:default]
22
+ options[:default] = defaults.flatten
23
+ key = "#{path}.#{action_name}#{key}"
24
+ end
25
+
26
+ if options[:default] && ActiveSupport::HtmlSafeTranslation.html_safe_translation_key?(key)
27
+ options[:default] = Array(options[:default]).map do |value|
28
+ value.is_a?(String) ? ERB::Util.html_escape(value) : value
29
+ end
16
30
  end
17
31
 
18
- I18n.translate(*args)
32
+ ActiveSupport::HtmlSafeTranslation.translate(key, **options)
19
33
  end
20
34
  alias :t :translate
21
35
 
22
- # Delegates to <tt>I18n.localize</tt>. Also aliased as <tt>l</tt>.
23
- def localize(*args)
24
- I18n.localize(*args)
36
+ # Delegates to `I18n.localize`.
37
+ def localize(object, **options)
38
+ I18n.localize(object, **options)
25
39
  end
26
40
  alias :l :localize
27
41
  end