actionview 6.1.7.2 → 7.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +268 -254
  3. data/MIT-LICENSE +1 -0
  4. data/README.rdoc +2 -2
  5. data/lib/action_view/base.rb +4 -7
  6. data/lib/action_view/buffers.rb +2 -2
  7. data/lib/action_view/cache_expiry.rb +46 -32
  8. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  9. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  10. data/lib/action_view/dependency_tracker.rb +6 -147
  11. data/lib/action_view/digestor.rb +7 -4
  12. data/lib/action_view/flows.rb +4 -4
  13. data/lib/action_view/gem_version.rb +5 -5
  14. data/lib/action_view/helpers/active_model_helper.rb +2 -2
  15. data/lib/action_view/helpers/asset_tag_helper.rb +95 -39
  16. data/lib/action_view/helpers/asset_url_helper.rb +16 -16
  17. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  18. data/lib/action_view/helpers/cache_helper.rb +52 -3
  19. data/lib/action_view/helpers/capture_helper.rb +4 -4
  20. data/lib/action_view/helpers/controller_helper.rb +2 -2
  21. data/lib/action_view/helpers/csp_helper.rb +1 -1
  22. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  23. data/lib/action_view/helpers/date_helper.rb +111 -43
  24. data/lib/action_view/helpers/debug_helper.rb +3 -1
  25. data/lib/action_view/helpers/form_helper.rb +211 -85
  26. data/lib/action_view/helpers/form_options_helper.rb +70 -33
  27. data/lib/action_view/helpers/form_tag_helper.rb +150 -53
  28. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  29. data/lib/action_view/helpers/number_helper.rb +17 -16
  30. data/lib/action_view/helpers/output_safety_helper.rb +4 -4
  31. data/lib/action_view/helpers/rendering_helper.rb +5 -6
  32. data/lib/action_view/helpers/sanitize_helper.rb +3 -3
  33. data/lib/action_view/helpers/tag_helper.rb +37 -8
  34. data/lib/action_view/helpers/tags/base.rb +5 -25
  35. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  36. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  37. data/lib/action_view/helpers/tags/file_field.rb +16 -0
  38. data/lib/action_view/helpers/tags/select.rb +1 -1
  39. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  40. data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
  41. data/lib/action_view/helpers/tags.rb +3 -2
  42. data/lib/action_view/helpers/text_helper.rb +25 -14
  43. data/lib/action_view/helpers/translation_helper.rb +12 -43
  44. data/lib/action_view/helpers/url_helper.rb +194 -123
  45. data/lib/action_view/helpers.rb +25 -25
  46. data/lib/action_view/layouts.rb +7 -4
  47. data/lib/action_view/lookup_context.rb +33 -52
  48. data/lib/action_view/model_naming.rb +2 -2
  49. data/lib/action_view/path_set.rb +16 -22
  50. data/lib/action_view/railtie.rb +19 -7
  51. data/lib/action_view/record_identifier.rb +1 -1
  52. data/lib/action_view/render_parser.rb +188 -0
  53. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  54. data/lib/action_view/renderer/partial_renderer.rb +1 -35
  55. data/lib/action_view/renderer/renderer.rb +4 -4
  56. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  57. data/lib/action_view/renderer/template_renderer.rb +6 -2
  58. data/lib/action_view/rendering.rb +3 -3
  59. data/lib/action_view/ripper_ast_parser.rb +198 -0
  60. data/lib/action_view/routing_url_for.rb +8 -5
  61. data/lib/action_view/template/error.rb +108 -13
  62. data/lib/action_view/template/handlers/erb.rb +6 -0
  63. data/lib/action_view/template/handlers.rb +3 -3
  64. data/lib/action_view/template/html.rb +3 -3
  65. data/lib/action_view/template/inline.rb +3 -3
  66. data/lib/action_view/template/raw_file.rb +3 -3
  67. data/lib/action_view/template/resolver.rb +89 -314
  68. data/lib/action_view/template/text.rb +3 -3
  69. data/lib/action_view/template/types.rb +14 -12
  70. data/lib/action_view/template.rb +18 -2
  71. data/lib/action_view/template_details.rb +66 -0
  72. data/lib/action_view/template_path.rb +64 -0
  73. data/lib/action_view/test_case.rb +7 -3
  74. data/lib/action_view/testing/resolvers.rb +11 -12
  75. data/lib/action_view/unbound_template.rb +33 -7
  76. data/lib/action_view/version.rb +1 -1
  77. data/lib/action_view/view_paths.rb +4 -4
  78. data/lib/action_view.rb +2 -3
  79. data/lib/assets/compiled/rails-ujs.js +36 -5
  80. 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