actionview 6.1.7.2 → 7.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +265 -261
  3. data/MIT-LICENSE +1 -0
  4. data/lib/action_view/base.rb +4 -7
  5. data/lib/action_view/buffers.rb +2 -2
  6. data/lib/action_view/cache_expiry.rb +46 -32
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  8. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  9. data/lib/action_view/dependency_tracker.rb +6 -147
  10. data/lib/action_view/digestor.rb +7 -4
  11. data/lib/action_view/flows.rb +4 -4
  12. data/lib/action_view/gem_version.rb +5 -5
  13. data/lib/action_view/helpers/active_model_helper.rb +2 -2
  14. data/lib/action_view/helpers/asset_tag_helper.rb +95 -39
  15. data/lib/action_view/helpers/asset_url_helper.rb +16 -16
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +52 -3
  18. data/lib/action_view/helpers/capture_helper.rb +4 -4
  19. data/lib/action_view/helpers/controller_helper.rb +2 -2
  20. data/lib/action_view/helpers/csp_helper.rb +1 -1
  21. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  22. data/lib/action_view/helpers/date_helper.rb +111 -43
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +211 -85
  25. data/lib/action_view/helpers/form_options_helper.rb +70 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +150 -53
  27. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  28. data/lib/action_view/helpers/number_helper.rb +17 -16
  29. data/lib/action_view/helpers/output_safety_helper.rb +4 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +5 -6
  31. data/lib/action_view/helpers/sanitize_helper.rb +3 -3
  32. data/lib/action_view/helpers/tag_helper.rb +37 -8
  33. data/lib/action_view/helpers/tags/base.rb +5 -25
  34. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  35. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  36. data/lib/action_view/helpers/tags/file_field.rb +16 -0
  37. data/lib/action_view/helpers/tags/select.rb +1 -1
  38. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  39. data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
  40. data/lib/action_view/helpers/tags.rb +3 -2
  41. data/lib/action_view/helpers/text_helper.rb +25 -14
  42. data/lib/action_view/helpers/translation_helper.rb +12 -43
  43. data/lib/action_view/helpers/url_helper.rb +194 -123
  44. data/lib/action_view/helpers.rb +25 -25
  45. data/lib/action_view/layouts.rb +7 -4
  46. data/lib/action_view/lookup_context.rb +33 -52
  47. data/lib/action_view/model_naming.rb +2 -2
  48. data/lib/action_view/path_set.rb +16 -22
  49. data/lib/action_view/railtie.rb +19 -7
  50. data/lib/action_view/record_identifier.rb +1 -1
  51. data/lib/action_view/render_parser.rb +188 -0
  52. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  53. data/lib/action_view/renderer/partial_renderer.rb +1 -35
  54. data/lib/action_view/renderer/renderer.rb +4 -4
  55. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  56. data/lib/action_view/renderer/template_renderer.rb +6 -2
  57. data/lib/action_view/rendering.rb +3 -3
  58. data/lib/action_view/ripper_ast_parser.rb +198 -0
  59. data/lib/action_view/routing_url_for.rb +8 -5
  60. data/lib/action_view/template/error.rb +108 -13
  61. data/lib/action_view/template/handlers/erb.rb +6 -0
  62. data/lib/action_view/template/handlers.rb +3 -3
  63. data/lib/action_view/template/html.rb +3 -3
  64. data/lib/action_view/template/inline.rb +3 -3
  65. data/lib/action_view/template/raw_file.rb +3 -3
  66. data/lib/action_view/template/resolver.rb +89 -314
  67. data/lib/action_view/template/text.rb +3 -3
  68. data/lib/action_view/template/types.rb +14 -12
  69. data/lib/action_view/template.rb +18 -2
  70. data/lib/action_view/template_details.rb +66 -0
  71. data/lib/action_view/template_path.rb +64 -0
  72. data/lib/action_view/test_case.rb +7 -3
  73. data/lib/action_view/testing/resolvers.rb +11 -12
  74. data/lib/action_view/unbound_template.rb +33 -7
  75. data/lib/action_view/version.rb +1 -1
  76. data/lib/action_view/view_paths.rb +4 -4
  77. data/lib/action_view.rb +2 -3
  78. data/lib/assets/compiled/rails-ujs.js +36 -5
  79. metadata +23 -16
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/helpers/javascript_helper"
4
3
  require "active_support/core_ext/array/access"
5
4
  require "active_support/core_ext/hash/keys"
6
5
  require "active_support/core_ext/string/output_safety"
6
+ require "action_view/helpers/tag_helper"
7
7
 
8
8
  module ActionView
9
9
  # = Action View URL Helpers
10
- module Helpers #:nodoc:
10
+ module Helpers # :nodoc:
11
11
  # Provides a set of methods for making links and getting URLs that
12
12
  # depend on the routing subsystem (see ActionDispatch::Routing).
13
13
  # This allows you to use the same format for links in views
@@ -29,6 +29,8 @@ module ActionView
29
29
  end
30
30
  end
31
31
 
32
+ mattr_accessor :button_to_generates_button_tag, default: false
33
+
32
34
  # Basic implementation of url_for to allow use helpers without routes existence
33
35
  def url_for(options = nil) # :nodoc:
34
36
  case options
@@ -83,35 +85,13 @@ module ActionView
83
85
  # # name
84
86
  # end
85
87
  #
88
+ # link_to(active_record_model)
89
+ #
86
90
  # ==== Options
87
91
  # * <tt>:data</tt> - This option can be used to add custom data attributes.
88
- # * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
89
- # create an HTML form and immediately submit the form for processing using
90
- # the HTTP verb specified. Useful for having links perform a POST operation
91
- # in dangerous actions like deleting a record (which search bots can follow
92
- # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
93
- # Note that if the user has JavaScript disabled, the request will fall back
94
- # to using GET. If <tt>href: '#'</tt> is used and the user has JavaScript
95
- # disabled clicking the link will have no effect. If you are relying on the
96
- # POST behavior, you should check for it in your controller's action by using
97
- # the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>patch?</tt>, or <tt>put?</tt>.
98
- # * <tt>remote: true</tt> - This will allow the unobtrusive JavaScript
99
- # driver to make an Ajax request to the URL in question instead of following
100
- # the link. The drivers each provide mechanisms for listening for the
101
- # completion of the Ajax request and performing JavaScript operations once
102
- # they're complete
103
- #
104
- # ==== Data attributes
105
- #
106
- # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
107
- # driver to prompt with the question specified (in this case, the
108
- # resulting text would be <tt>question?</tt>. If the user accepts, the
109
- # link is processed normally, otherwise no action is taken.
110
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the
111
- # name for a disabled version of the link. This feature is provided by
112
- # the unobtrusive JavaScript driver.
113
92
  #
114
93
  # ==== Examples
94
+ #
115
95
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
116
96
  # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
117
97
  # your application on resources and use
@@ -144,6 +124,12 @@ module ActionView
144
124
  # link_to nil, "http://example.com"
145
125
  # # => <a href="http://www.example.com">http://www.example.com</a>
146
126
  #
127
+ # More concise yet, when +name+ is an Active Record model that defines a
128
+ # +to_s+ method returning a default value or a model instance attribute
129
+ #
130
+ # link_to @profile
131
+ # # => <a href="http://www.example.com/profiles/1">Eileen</a>
132
+ #
147
133
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
148
134
  #
149
135
  # <%= link_to(@profile) do %>
@@ -179,27 +165,54 @@ module ActionView
179
165
  # link_to "Nonsense search", searches_path(foo: "bar", baz: "quux")
180
166
  # # => <a href="/searches?foo=bar&baz=quux">Nonsense search</a>
181
167
  #
182
- # The only option specific to +link_to+ (<tt>:method</tt>) is used as follows:
168
+ # You can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
169
+ #
170
+ # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
171
+ # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
183
172
  #
184
- # link_to("Destroy", "http://www.example.com", method: :delete)
185
- # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
173
+ # ==== Deprecated: Rails UJS Attributes
186
174
  #
187
- # You can also use custom data attributes using the <tt>:data</tt> option:
175
+ # Prior to Rails 7, Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following Rails 7,
176
+ # this library is no longer on by default. This library integrated with the following options:
177
+ #
178
+ # * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
179
+ # create an HTML form and immediately submit the form for processing using
180
+ # the HTTP verb specified. Useful for having links perform a POST operation
181
+ # in dangerous actions like deleting a record (which search bots can follow
182
+ # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
183
+ # Note that if the user has JavaScript disabled, the request will fall back
184
+ # to using GET. If <tt>href: '#'</tt> is used and the user has JavaScript
185
+ # disabled clicking the link will have no effect. If you are relying on the
186
+ # POST behavior, you should check for it in your controller's action by using
187
+ # the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>patch?</tt>, or <tt>put?</tt>.
188
+ # * <tt>remote: true</tt> - This will allow <tt>@rails/ujs</tt>
189
+ # to make an Ajax request to the URL in question instead of following
190
+ # the link.
191
+ #
192
+ # <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
193
+ #
194
+ # * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
195
+ # to prompt with the question specified (in this case, the
196
+ # resulting text would be <tt>question?</tt>). If the user accepts, the
197
+ # link is processed normally, otherwise no action is taken.
198
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the
199
+ # name for a disabled version of the link.
200
+ #
201
+ # ===== Rails UJS Examples
202
+ #
203
+ # link_to "Remove Profile", profile_path(@profile), method: :delete
204
+ # # => <a href="/profiles/1" rel="nofollow" data-method="delete">Remove Profile</a>
188
205
  #
189
206
  # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
190
207
  # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
191
208
  #
192
- # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
193
- #
194
- # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
195
- # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
196
209
  def link_to(name = nil, options = nil, html_options = nil, &block)
197
210
  html_options, options, name = options, name, block if block_given?
198
211
  options ||= {}
199
212
 
200
213
  html_options = convert_options_to_data_attributes(options, html_options)
201
214
 
202
- url = url_for(options)
215
+ url = url_target(name, options)
203
216
  html_options["href"] ||= url
204
217
 
205
218
  content_tag("a", name || url, html_options, &block)
@@ -212,50 +225,59 @@ module ActionView
212
225
  # using the +link_to+ method with the <tt>:method</tt> modifier as described in
213
226
  # the +link_to+ documentation.
214
227
  #
215
- # By default, the generated form element has a class name of <tt>button_to</tt>
216
- # to allow styling of the form itself and its children. This can be changed
217
- # using the <tt>:form_class</tt> modifier within +html_options+. You can control
218
- # the form submission and input element behavior using +html_options+.
219
- # This method accepts the <tt>:method</tt> modifier described in the +link_to+ documentation.
220
- # If no <tt>:method</tt> modifier is given, it will default to performing a POST operation.
221
- # You can also disable the button by passing <tt>disabled: true</tt> in +html_options+.
222
- # If you are using RESTful routes, you can pass the <tt>:method</tt>
223
- # to change the HTTP verb used to submit the form.
228
+ # You can control the form and button behavior with +html_options+. Most
229
+ # values in +html_options+ are passed through to the button element. For
230
+ # example, passing a +:class+ option within +html_options+ will set the
231
+ # class attribute of the button element.
232
+ #
233
+ # The class attribute of the form element can be set by passing a
234
+ # +:form_class+ option within +html_options+. It defaults to
235
+ # <tt>"button_to"</tt> to allow styling of the form and its children.
236
+ #
237
+ # The form submits a POST request by default. You can specify a different
238
+ # HTTP verb via the +:method+ option within +html_options+.
224
239
  #
225
240
  # ==== Options
226
- # The +options+ hash accepts the same options as +url_for+.
241
+ # The +options+ hash accepts the same options as +url_for+. To generate a
242
+ # <tt><form></tt> element without an <tt>[action]</tt> attribute, pass
243
+ # <tt>false</tt>:
244
+ #
245
+ # <%= button_to "New", false %>
246
+ # # => "<form method="post" class="button_to">
247
+ # # <button type="submit">New</button>
248
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
249
+ # # </form>"
250
+ #
251
+ # Most values in +html_options+ are passed through to the button element,
252
+ # but there are a few special options:
227
253
  #
228
- # There are a few special +html_options+:
229
254
  # * <tt>:method</tt> - \Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
230
255
  # <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
231
256
  # * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
232
257
  # * <tt>:data</tt> - This option can be used to add custom data attributes.
233
- # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
234
- # submit behavior. By default this behavior is an ajax submit.
235
258
  # * <tt>:form</tt> - This hash will be form attributes
236
259
  # * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
237
260
  # be placed
238
261
  # * <tt>:params</tt> - \Hash of parameters to be rendered as hidden fields within the form.
239
262
  #
240
- # ==== Data attributes
241
- #
242
- # * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
243
- # prompt with the question specified. If the user accepts, the link is
244
- # processed normally, otherwise no action is taken.
245
- # * <tt>:disable_with</tt> - Value of this parameter will be
246
- # used as the value for a disabled version of the submit
247
- # button when the form is submitted. This feature is provided
248
- # by the unobtrusive JavaScript driver.
249
- #
250
263
  # ==== Examples
251
264
  # <%= button_to "New", action: "new" %>
252
265
  # # => "<form method="post" action="/controller/new" class="button_to">
253
- # # <input value="New" type="submit" />
266
+ # # <button type="submit">New</button>
267
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
254
268
  # # </form>"
255
269
  #
256
270
  # <%= button_to "New", new_article_path %>
257
271
  # # => "<form method="post" action="/articles/new" class="button_to">
258
- # # <input value="New" type="submit" />
272
+ # # <button type="submit">New</button>
273
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
274
+ # # </form>"
275
+ #
276
+ # <%= button_to "New", new_article_path, params: { time: Time.now } %>
277
+ # # => "<form method="post" action="/articles/new" class="button_to">
278
+ # # <button type="submit">New</button>
279
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
280
+ # # <input type="hidden" name="time" value="2021-04-08 14:06:09 -0500" autocomplete="off">
259
281
  # # </form>"
260
282
  #
261
283
  # <%= button_to [:make_happy, @user] do %>
@@ -265,49 +287,64 @@ module ActionView
265
287
  # # <button type="submit">
266
288
  # # Make happy <strong><%= @user.name %></strong>
267
289
  # # </button>
290
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
268
291
  # # </form>"
269
292
  #
270
293
  # <%= button_to "New", { action: "new" }, form_class: "new-thing" %>
271
294
  # # => "<form method="post" action="/controller/new" class="new-thing">
272
- # # <input value="New" type="submit" />
295
+ # # <button type="submit">New</button>
296
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
273
297
  # # </form>"
274
298
  #
275
- #
276
- # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
277
- # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
278
- # # <input value="Create" type="submit" />
279
- # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
299
+ # <%= button_to "Create", { action: "create" }, form: { "data-type" => "json" } %>
300
+ # # => "<form method="post" action="/images/create" class="button_to" data-type="json">
301
+ # # <button type="submit">Create</button>
302
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
280
303
  # # </form>"
281
304
  #
305
+ # ==== Deprecated: Rails UJS Attributes
282
306
  #
283
- # <%= button_to "Delete Image", { action: "delete", id: @image.id },
284
- # method: :delete, data: { confirm: "Are you sure?" } %>
285
- # # => "<form method="post" action="/images/delete/1" class="button_to">
286
- # # <input type="hidden" name="_method" value="delete" />
287
- # # <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
288
- # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
289
- # # </form>"
307
+ # Prior to Rails 7, Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following Rails 7,
308
+ # this library is no longer on by default. This library integrated with the following options:
309
+ #
310
+ # * <tt>:remote</tt> - If set to true, will allow <tt>@rails/ujs</tt> to control the
311
+ # submit behavior. By default this behavior is an Ajax submit.
312
+ #
313
+ # <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
314
+ #
315
+ # * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
316
+ # to prompt with the question specified (in this case, the
317
+ # resulting text would be <tt>question?</tt>). If the user accepts, the
318
+ # button is processed normally, otherwise no action is taken.
319
+ # * <tt>:disable_with</tt> - Value of this parameter will be
320
+ # used as the value for a disabled version of the submit
321
+ # button when the form is submitted.
322
+ #
323
+ # ===== Rails UJS Examples
290
324
  #
325
+ # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
326
+ # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
327
+ # # <button type="submit">Create</button>
328
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
329
+ # # </form>"
291
330
  #
292
- # <%= button_to('Destroy', 'http://www.example.com',
293
- # method: :delete, remote: true, data: { confirm: 'Are you sure?', disable_with: 'loading...' }) %>
294
- # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
295
- # # <input name='_method' value='delete' type='hidden' />
296
- # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
297
- # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
298
- # # </form>"
299
- # #
300
331
  def button_to(name = nil, options = nil, html_options = nil, &block)
301
332
  html_options, options = options, name if block_given?
302
- options ||= {}
303
333
  html_options ||= {}
304
334
  html_options = html_options.stringify_keys
305
335
 
306
- url = options.is_a?(String) ? options : url_for(options)
336
+ url =
337
+ case options
338
+ when FalseClass then nil
339
+ else url_for(options)
340
+ end
341
+
307
342
  remote = html_options.delete("remote")
308
343
  params = html_options.delete("params")
309
344
 
310
- method = html_options.delete("method").to_s
345
+ authenticity_token = html_options.delete("authenticity_token")
346
+
347
+ method = (html_options.delete("method").presence || method_for_options(options)).to_s
311
348
  method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
312
349
 
313
350
  form_method = method == "get" ? "get" : "post"
@@ -319,7 +356,7 @@ module ActionView
319
356
 
320
357
  request_token_tag = if form_method == "post"
321
358
  request_method = method.empty? ? "post" : method
322
- token_tag(nil, form_options: { action: url, method: request_method })
359
+ token_tag(authenticity_token, form_options: { action: url, method: request_method })
323
360
  else
324
361
  ""
325
362
  end
@@ -329,6 +366,8 @@ module ActionView
329
366
 
330
367
  button = if block_given?
331
368
  content_tag("button", html_options, &block)
369
+ elsif button_to_generates_button_tag
370
+ content_tag("button", name || url, html_options, &block)
332
371
  else
333
372
  html_options["value"] = name || url
334
373
  tag("input", html_options)
@@ -453,7 +492,7 @@ module ActionView
453
492
  # * <tt>:body</tt> - Preset the body of the email.
454
493
  # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
455
494
  # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
456
- # * <tt>:reply_to</tt> - Preset the Reply-To field of the email.
495
+ # * <tt>:reply_to</tt> - Preset the +Reply-To+ field of the email.
457
496
  #
458
497
  # ==== Obfuscation
459
498
  # Prior to Rails 4.0, +mail_to+ provided options for encoding the address
@@ -467,9 +506,9 @@ module ActionView
467
506
  # mail_to "me@domain.com", "My email"
468
507
  # # => <a href="mailto:me@domain.com">My email</a>
469
508
  #
470
- # mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
509
+ # mail_to "me@domain.com", cc: "ccaddress@domain.com",
471
510
  # subject: "This is an example email"
472
- # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
511
+ # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">me@domain.com</a>
473
512
  #
474
513
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
475
514
  #
@@ -480,7 +519,7 @@ module ActionView
480
519
  # <strong>Email me:</strong> <span>me@domain.com</span>
481
520
  # </a>
482
521
  def mail_to(email_address, name = nil, html_options = {}, &block)
483
- html_options, name = name, nil if block_given?
522
+ html_options, name = name, nil if name.is_a?(Hash)
484
523
  html_options = (html_options || {}).stringify_keys
485
524
 
486
525
  extras = %w{ cc bcc body subject reply_to }.map! { |item|
@@ -583,29 +622,37 @@ module ActionView
583
622
  end
584
623
  end
585
624
 
586
- # Creates an SMS anchor link tag to the specified +phone_number+, which is
587
- # also used as the name of the link unless +name+ is specified. Additional
588
- # HTML attributes for the link can be passed in +html_options+.
625
+ # Creates an SMS anchor link tag to the specified +phone_number+. When the
626
+ # link is clicked, the default SMS messaging app is opened ready to send a
627
+ # message to the linked phone number. If the +body+ option is specified,
628
+ # the contents of the message will be preset to +body+.
589
629
  #
590
- # When clicked, an SMS message is prepopulated with the passed phone number
591
- # and optional +body+ value.
630
+ # If +name+ is not specified, +phone_number+ will be used as the name of
631
+ # the link.
592
632
  #
593
- # +sms_to+ has a +body+ option for customizing the SMS message itself by
594
- # passing special keys to +html_options+.
633
+ # A +country_code+ option is supported, which prepends a plus sign and the
634
+ # given country code to the linked phone number. For example,
635
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
636
+ # phone number.
637
+ #
638
+ # Additional HTML attributes for the link can be passed via +html_options+.
595
639
  #
596
640
  # ==== Options
641
+ # * <tt>:country_code</tt> - Prepend the country code to the phone number.
597
642
  # * <tt>:body</tt> - Preset the body of the message.
598
643
  #
599
644
  # ==== Examples
600
645
  # sms_to "5155555785"
601
646
  # # => <a href="sms:5155555785;">5155555785</a>
602
647
  #
648
+ # sms_to "5155555785", country_code: "01"
649
+ # # => <a href="sms:+015155555785;">5155555785</a>
650
+ #
603
651
  # sms_to "5155555785", "Text me"
604
652
  # # => <a href="sms:5155555785;">Text me</a>
605
653
  #
606
- # sms_to "5155555785", "Text me",
607
- # body: "Hello Jim I have a question about your product."
608
- # # => <a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
654
+ # sms_to "5155555785", body: "I have a question about your product."
655
+ # # => <a href="sms:5155555785;?body=I%20have%20a%20question%20about%20your%20product">5155555785</a>
609
656
  #
610
657
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
611
658
  #
@@ -616,46 +663,47 @@ module ActionView
616
663
  # <strong>Text me:</strong>
617
664
  # </a>
618
665
  def sms_to(phone_number, name = nil, html_options = {}, &block)
619
- html_options, name = name, nil if block_given?
666
+ html_options, name = name, nil if name.is_a?(Hash)
620
667
  html_options = (html_options || {}).stringify_keys
621
668
 
622
- extras = %w{ body }.map! { |item|
623
- option = html_options.delete(item).presence || next
624
- "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
625
- }.compact
626
- extras = extras.empty? ? "" : "?&" + extras.join("&")
669
+ country_code = html_options.delete("country_code").presence
670
+ country_code = country_code ? "+#{ERB::Util.url_encode(country_code)}" : ""
671
+
672
+ body = html_options.delete("body").presence
673
+ body = body ? "?&body=#{ERB::Util.url_encode(body)}" : ""
627
674
 
628
675
  encoded_phone_number = ERB::Util.url_encode(phone_number)
629
- html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
676
+ html_options["href"] = "sms:#{country_code}#{encoded_phone_number};#{body}"
630
677
 
631
678
  content_tag("a", name || phone_number, html_options, &block)
632
679
  end
633
680
 
634
- # Creates a TEL anchor link tag to the specified +phone_number+, which is
635
- # also used as the name of the link unless +name+ is specified. Additional
636
- # HTML attributes for the link can be passed in +html_options+.
681
+ # Creates a TEL anchor link tag to the specified +phone_number+. When the
682
+ # link is clicked, the default app to make phone calls is opened and
683
+ # prepopulated with the phone number.
637
684
  #
638
- # When clicked, the default app to make calls is opened, and it
639
- # is prepopulated with the passed phone number and optional
640
- # +country_code+ value.
685
+ # If +name+ is not specified, +phone_number+ will be used as the name of
686
+ # the link.
641
687
  #
642
- # +phone_to+ has an optional +country_code+ option which automatically adds the country
643
- # code as well as the + sign in the phone numer that gets prepopulated,
644
- # for example if +country_code: "01"+ +\+01+ will be prepended to the
645
- # phone numer, by passing special keys to +html_options+.
688
+ # A +country_code+ option is supported, which prepends a plus sign and the
689
+ # given country code to the linked phone number. For example,
690
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
691
+ # phone number.
692
+ #
693
+ # Additional HTML attributes for the link can be passed via +html_options+.
646
694
  #
647
695
  # ==== Options
648
- # * <tt>:country_code</tt> - Prepends the country code to the number
696
+ # * <tt>:country_code</tt> - Prepends the country code to the phone number
649
697
  #
650
698
  # ==== Examples
651
699
  # phone_to "1234567890"
652
700
  # # => <a href="tel:1234567890">1234567890</a>
653
701
  #
654
702
  # phone_to "1234567890", "Phone me"
655
- # # => <a href="tel:134567890">Phone me</a>
703
+ # # => <a href="tel:1234567890">Phone me</a>
656
704
  #
657
- # phone_to "1234567890", "Phone me", country_code: "01"
658
- # # => <a href="tel:+015155555785">Phone me</a>
705
+ # phone_to "1234567890", country_code: "01"
706
+ # # => <a href="tel:+011234567890">1234567890</a>
659
707
  #
660
708
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
661
709
  #
@@ -666,7 +714,7 @@ module ActionView
666
714
  # <strong>Phone me:</strong>
667
715
  # </a>
668
716
  def phone_to(phone_number, name = nil, html_options = {}, &block)
669
- html_options, name = name, nil if block_given?
717
+ html_options, name = name, nil if name.is_a?(Hash)
670
718
  html_options = (html_options || {}).stringify_keys
671
719
 
672
720
  country_code = html_options.delete("country_code").presence
@@ -694,6 +742,14 @@ module ActionView
694
742
  end
695
743
  end
696
744
 
745
+ def url_target(name, options)
746
+ if name.respond_to?(:model_name) && options.is_a?(Hash) && options.empty?
747
+ url_for(name)
748
+ else
749
+ url_for(options)
750
+ end
751
+ end
752
+
697
753
  def link_to_remote_options?(options)
698
754
  if options.is_a?(Hash)
699
755
  options.delete("remote") || options.delete(:remote)
@@ -711,6 +767,16 @@ module ActionView
711
767
  html_options["data-method"] = method
712
768
  end
713
769
 
770
+ def method_for_options(options)
771
+ if options.is_a?(Array)
772
+ method_for_options(options.last)
773
+ elsif options.respond_to?(:persisted?)
774
+ options.persisted? ? :patch : :post
775
+ elsif options.respond_to?(:to_model)
776
+ method_for_options(options.to_model)
777
+ end
778
+ end
779
+
714
780
  STRINGIFIED_COMMON_METHODS = {
715
781
  get: "get",
716
782
  delete: "delete",
@@ -726,7 +792,12 @@ module ActionView
726
792
 
727
793
  def token_tag(token = nil, form_options: {})
728
794
  if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
729
- token ||= form_authenticity_token(form_options: form_options)
795
+ token =
796
+ if token == true || token.nil?
797
+ form_authenticity_token(form_options: form_options.merge(authenticity_token: token))
798
+ else
799
+ token
800
+ end
730
801
  tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token, autocomplete: "off")
731
802
  else
732
803
  ""
@@ -1,34 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/benchmarkable"
4
+ require "action_view/helpers/capture_helper"
5
+ require "action_view/helpers/output_safety_helper"
6
+ require "action_view/helpers/tag_helper"
7
+ require "action_view/helpers/url_helper"
8
+ require "action_view/helpers/sanitize_helper"
9
+ require "action_view/helpers/text_helper"
10
+ require "action_view/helpers/active_model_helper"
11
+ require "action_view/helpers/asset_tag_helper"
12
+ require "action_view/helpers/asset_url_helper"
13
+ require "action_view/helpers/atom_feed_helper"
14
+ require "action_view/helpers/cache_helper"
15
+ require "action_view/helpers/controller_helper"
16
+ require "action_view/helpers/csp_helper"
17
+ require "action_view/helpers/csrf_helper"
18
+ require "action_view/helpers/date_helper"
19
+ require "action_view/helpers/debug_helper"
20
+ require "action_view/helpers/form_tag_helper"
21
+ require "action_view/helpers/form_helper"
22
+ require "action_view/helpers/form_options_helper"
23
+ require "action_view/helpers/javascript_helper"
24
+ require "action_view/helpers/number_helper"
25
+ require "action_view/helpers/rendering_helper"
26
+ require "action_view/helpers/translation_helper"
4
27
 
5
- module ActionView #:nodoc:
6
- module Helpers #:nodoc:
28
+ module ActionView # :nodoc:
29
+ module Helpers # :nodoc:
7
30
  extend ActiveSupport::Autoload
8
31
 
9
- autoload :ActiveModelHelper
10
- autoload :AssetTagHelper
11
- autoload :AssetUrlHelper
12
- autoload :AtomFeedHelper
13
- autoload :CacheHelper
14
- autoload :CaptureHelper
15
- autoload :ControllerHelper
16
- autoload :CspHelper
17
- autoload :CsrfHelper
18
- autoload :DateHelper
19
- autoload :DebugHelper
20
- autoload :FormHelper
21
- autoload :FormOptionsHelper
22
- autoload :FormTagHelper
23
- autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
24
- autoload :NumberHelper
25
- autoload :OutputSafetyHelper
26
- autoload :RenderingHelper
27
- autoload :SanitizeHelper
28
- autoload :TagHelper
29
- autoload :TextHelper
30
- autoload :TranslationHelper
31
- autoload :UrlHelper
32
32
  autoload :Tags
33
33
 
34
34
  def self.eager_load!
@@ -183,7 +183,7 @@ module ActionView
183
183
  # be rendered directly, without wrapping a layout around the rendered view.
184
184
  #
185
185
  # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
186
- # #<tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
186
+ # <tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
187
187
  #
188
188
  # == Using a different layout in the action render call
189
189
  #
@@ -255,14 +255,17 @@ module ActionView
255
255
  # true:: raise an ArgumentError
256
256
  # nil:: Force default layout behavior with inheritance
257
257
  #
258
- # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+ or +nil+
258
+ # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+, or +nil+
259
259
  # with the same meaning as described above.
260
+ #
260
261
  # ==== Parameters
262
+ #
261
263
  # * <tt>layout</tt> - The layout to use.
262
264
  #
263
265
  # ==== Options (conditions)
264
- # * :only - A list of actions to apply this layout to.
265
- # * :except - Apply this layout to all actions but this one.
266
+ #
267
+ # * +:only+ - A list of actions to apply this layout to.
268
+ # * +:except+ - Apply this layout to all actions but this one.
266
269
  def layout(layout, conditions = {})
267
270
  include LayoutConditions unless conditions.empty?
268
271