actionview 5.1.7 → 5.2.8.1

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -178
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/action_view/base.rb +8 -10
  6. data/lib/action_view/buffers.rb +2 -0
  7. data/lib/action_view/context.rb +2 -2
  8. data/lib/action_view/dependency_tracker.rb +2 -0
  9. data/lib/action_view/digestor.rb +7 -7
  10. data/lib/action_view/flows.rb +2 -0
  11. data/lib/action_view/gem_version.rb +5 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +9 -3
  13. data/lib/action_view/helpers/asset_tag_helper.rb +180 -34
  14. data/lib/action_view/helpers/asset_url_helper.rb +19 -17
  15. data/lib/action_view/helpers/atom_feed_helper.rb +3 -1
  16. data/lib/action_view/helpers/cache_helper.rb +24 -14
  17. data/lib/action_view/helpers/capture_helper.rb +9 -7
  18. data/lib/action_view/helpers/controller_helper.rb +3 -1
  19. data/lib/action_view/helpers/csp_helper.rb +24 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +4 -2
  21. data/lib/action_view/helpers/date_helper.rb +7 -5
  22. data/lib/action_view/helpers/debug_helper.rb +4 -2
  23. data/lib/action_view/helpers/form_helper.rb +53 -70
  24. data/lib/action_view/helpers/form_options_helper.rb +23 -17
  25. data/lib/action_view/helpers/form_tag_helper.rb +23 -11
  26. data/lib/action_view/helpers/javascript_helper.rb +20 -5
  27. data/lib/action_view/helpers/number_helper.rb +2 -0
  28. data/lib/action_view/helpers/output_safety_helper.rb +2 -0
  29. data/lib/action_view/helpers/record_tag_helper.rb +3 -1
  30. data/lib/action_view/helpers/rendering_helper.rb +3 -1
  31. data/lib/action_view/helpers/sanitize_helper.rb +3 -1
  32. data/lib/action_view/helpers/tag_helper.rb +39 -8
  33. data/lib/action_view/helpers/tags/base.rb +12 -10
  34. data/lib/action_view/helpers/tags/check_box.rb +3 -1
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -0
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +2 -0
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -0
  39. data/lib/action_view/helpers/tags/collection_select.rb +3 -1
  40. data/lib/action_view/helpers/tags/color_field.rb +3 -1
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -0
  42. data/lib/action_view/helpers/tags/date_select.rb +3 -1
  43. data/lib/action_view/helpers/tags/datetime_field.rb +3 -1
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -1
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +2 -4
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -0
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +2 -0
  54. data/lib/action_view/helpers/tags/placeholderable.rb +2 -0
  55. data/lib/action_view/helpers/tags/radio_button.rb +3 -1
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +2 -0
  58. data/lib/action_view/helpers/tags/select.rb +4 -2
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +3 -1
  61. data/lib/action_view/helpers/tags/text_field.rb +3 -1
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -0
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +2 -0
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -0
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +9 -7
  70. data/lib/action_view/helpers/translation_helper.rb +17 -5
  71. data/lib/action_view/helpers/url_helper.rb +28 -4
  72. data/lib/action_view/helpers.rb +4 -0
  73. data/lib/action_view/layouts.rb +7 -5
  74. data/lib/action_view/log_subscriber.rb +5 -3
  75. data/lib/action_view/lookup_context.rb +4 -4
  76. data/lib/action_view/model_naming.rb +2 -0
  77. data/lib/action_view/path_set.rb +2 -0
  78. data/lib/action_view/railtie.rb +11 -2
  79. data/lib/action_view/record_identifier.rb +2 -0
  80. data/lib/action_view/renderer/abstract_renderer.rb +2 -0
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +4 -2
  82. data/lib/action_view/renderer/partial_renderer.rb +13 -11
  83. data/lib/action_view/renderer/renderer.rb +2 -0
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +5 -1
  85. data/lib/action_view/renderer/template_renderer.rb +2 -0
  86. data/lib/action_view/rendering.rb +3 -5
  87. data/lib/action_view/routing_url_for.rb +2 -0
  88. data/lib/action_view/tasks/cache_digests.rake +2 -0
  89. data/lib/action_view/template/error.rb +2 -3
  90. data/lib/action_view/template/handlers/builder.rb +3 -4
  91. data/lib/action_view/template/handlers/erb/erubi.rb +2 -0
  92. data/lib/action_view/template/handlers/erb.rb +5 -9
  93. data/lib/action_view/template/handlers/html.rb +2 -0
  94. data/lib/action_view/template/handlers/raw.rb +2 -0
  95. data/lib/action_view/template/handlers.rb +3 -1
  96. data/lib/action_view/template/html.rb +3 -1
  97. data/lib/action_view/template/resolver.rb +7 -6
  98. data/lib/action_view/template/text.rb +3 -1
  99. data/lib/action_view/template/types.rb +3 -1
  100. data/lib/action_view/template.rb +6 -4
  101. data/lib/action_view/test_case.rb +21 -5
  102. data/lib/action_view/testing/resolvers.rb +3 -1
  103. data/lib/action_view/version.rb +2 -0
  104. data/lib/action_view/view_paths.rb +3 -3
  105. data/lib/action_view.rb +4 -3
  106. data/lib/assets/compiled/rails-ujs.js +52 -15
  107. metadata +15 -16
  108. data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +0 -9
  109. data/lib/action_view/template/handlers/erb/erubis.rb +0 -81
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/output_safety"
2
4
 
3
5
  module ActionView
4
6
  # = Action View Capture Helper
5
- module Helpers
7
+ module Helpers #:nodoc:
6
8
  # CaptureHelper exposes methods to let you extract generated markup which
7
9
  # can be used in other parts of a template or layout file.
8
10
  #
9
11
  # It provides a method to capture blocks into variables through capture and
10
- # a way to capture a block of markup for use in a layout through content_for.
12
+ # a way to capture a block of markup for use in a layout through {content_for}[rdoc-ref:ActionView::Helpers::CaptureHelper#content_for].
11
13
  module CaptureHelper
12
14
  # The capture method extracts part of a template as a String object.
13
15
  # You can then use this object anywhere in your templates, layout, or helpers.
@@ -42,7 +44,7 @@ module ActionView
42
44
  end
43
45
  end
44
46
 
45
- # Calling content_for stores a block of markup in an identifier for later use.
47
+ # Calling <tt>content_for</tt> stores a block of markup in an identifier for later use.
46
48
  # In order to access this stored content in other templates, helper modules
47
49
  # or the layout, you would pass the identifier as an argument to <tt>content_for</tt>.
48
50
  #
@@ -108,7 +110,7 @@ module ActionView
108
110
  # That will place +script+ tags for your default set of JavaScript files on the page;
109
111
  # this technique is useful if you'll only be using these scripts in a few views.
110
112
  #
111
- # Note that content_for concatenates (default) the blocks it is given for a particular
113
+ # Note that <tt>content_for</tt> concatenates (default) the blocks it is given for a particular
112
114
  # identifier in order. For example:
113
115
  #
114
116
  # <% content_for :navigation do %>
@@ -125,7 +127,7 @@ module ActionView
125
127
  #
126
128
  # <ul><%= content_for :navigation %></ul>
127
129
  #
128
- # If the flush parameter is true content_for replaces the blocks it is given. For example:
130
+ # If the flush parameter is +true+ <tt>content_for</tt> replaces the blocks it is given. For example:
129
131
  #
130
132
  # <% content_for :navigation do %>
131
133
  # <li><%= link_to 'Home', action: 'index' %></li>
@@ -145,7 +147,7 @@ module ActionView
145
147
  #
146
148
  # <% content_for :script, javascript_include_tag(:defaults) %>
147
149
  #
148
- # WARNING: content_for is ignored in caches. So you shouldn't use it for elements that will be fragment cached.
150
+ # WARNING: <tt>content_for</tt> is ignored in caches. So you shouldn't use it for elements that will be fragment cached.
149
151
  def content_for(name, content = nil, options = {}, &block)
150
152
  if content || block_given?
151
153
  if block_given?
@@ -172,7 +174,7 @@ module ActionView
172
174
  result unless content
173
175
  end
174
176
 
175
- # content_for? checks whether any content has been captured yet using `content_for`.
177
+ # <tt>content_for?</tt> checks whether any content has been captured yet using <tt>content_for</tt>.
176
178
  # Useful to render parts of your layout differently based on what is in your views.
177
179
  #
178
180
  # <%# This is the layout %>
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/attr_internal"
2
4
 
3
5
  module ActionView
4
- module Helpers
6
+ module Helpers #:nodoc:
5
7
  # This module keeps all methods and behavior in ActionView
6
8
  # that simply delegates to the controller.
7
9
  module ControllerHelper #:nodoc:
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ # = Action View CSP Helper
5
+ module Helpers #:nodoc:
6
+ module CspHelper
7
+ # Returns a meta tag "csp-nonce" with the per-session nonce value
8
+ # for allowing inline <script> tags.
9
+ #
10
+ # <head>
11
+ # <%= csp_meta_tag %>
12
+ # </head>
13
+ #
14
+ # This is used by the Rails UJS helper to create dynamically
15
+ # loaded inline <script> elements.
16
+ #
17
+ def csp_meta_tag
18
+ if content_security_policy?
19
+ tag("meta", name: "csp-nonce", content: content_security_policy_nonce)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # = Action View CSRF Helper
3
- module Helpers
5
+ module Helpers #:nodoc:
4
6
  module CsrfHelper
5
7
  # Returns meta tags "csrf-param" and "csrf-token" with the name of the cross-site
6
8
  # request forgery protection parameter and token, respectively.
@@ -15,7 +17,7 @@ module ActionView
15
17
  # You don't need to use these tags for regular forms as they generate their own hidden fields.
16
18
  #
17
19
  # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
18
- # "X-CSRF-Token" HTTP header. If you are using jQuery with jquery-rails this happens automatically.
20
+ # "X-CSRF-Token" HTTP header. If you are using rails-ujs this happens automatically.
19
21
  #
20
22
  def csrf_meta_tags
21
23
  if protect_against_forgery?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "date"
2
4
  require "action_view/helpers/tag_helper"
3
5
  require "active_support/core_ext/array/extract_options"
@@ -7,7 +9,7 @@ require "active_support/core_ext/object/acts_like"
7
9
  require "active_support/core_ext/object/with_options"
8
10
 
9
11
  module ActionView
10
- module Helpers
12
+ module Helpers #:nodoc:
11
13
  # = Action View Date Helpers
12
14
  #
13
15
  # The Date Helper primarily creates select/option tags for different kinds of dates and times or date and time
@@ -114,7 +116,7 @@ module ActionView
114
116
  when 10..19 then locale.t :less_than_x_seconds, count: 20
115
117
  when 20..39 then locale.t :half_a_minute
116
118
  when 40..59 then locale.t :less_than_x_minutes, count: 1
117
- else locale.t :x_minutes, count: 1
119
+ else locale.t :x_minutes, count: 1
118
120
  end
119
121
 
120
122
  when 2...45 then locale.t :x_minutes, count: distance_in_minutes
@@ -129,7 +131,7 @@ module ActionView
129
131
  when 43200...86400 then locale.t :about_x_months, count: (distance_in_minutes.to_f / 43200.0).round
130
132
  # 60 days up to 365 days
131
133
  when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
132
- else
134
+ else
133
135
  from_year = from_time.year
134
136
  from_year += 1 if from_time.month >= 3
135
137
  to_year = to_time.year
@@ -1007,7 +1009,7 @@ module ActionView
1007
1009
  select_options[:disabled] = "disabled" if @options[:disabled]
1008
1010
  select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
1009
1011
 
1010
- select_html = "\n"
1012
+ select_html = "\n".dup
1011
1013
  select_html << content_tag("option".freeze, "", value: "") + "\n" if @options[:include_blank]
1012
1014
  select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
1013
1015
  select_html << select_options_as_html
@@ -1089,7 +1091,7 @@ module ActionView
1089
1091
  # Given an ordering of datetime components, create the selection HTML
1090
1092
  # and join them with their appropriate separators.
1091
1093
  def build_selects_from_types(order)
1092
- select = ""
1094
+ select = "".dup
1093
1095
  first_visible = order.find { |type| !@options[:"discard_#{type}"] }
1094
1096
  order.reverse_each do |type|
1095
1097
  separator = separator(type) unless type == first_visible # don't add before first visible field
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # = Action View Debug Helper
3
5
  #
4
6
  # Provides a set of methods for making it easier to debug Rails objects.
5
- module Helpers
7
+ module Helpers #:nodoc:
6
8
  module DebugHelper
7
9
  include TagHelper
8
10
 
@@ -22,7 +24,7 @@ module ActionView
22
24
  # created_at:
23
25
  # </pre>
24
26
  def debug(object)
25
- Marshal::dump(object)
27
+ Marshal.dump(object)
26
28
  object = ERB::Util.html_escape(object.to_yaml)
27
29
  content_tag(:pre, object, class: "debug_dump")
28
30
  rescue # errors from Marshal or YAML
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "cgi"
2
4
  require "action_view/helpers/date_helper"
3
5
  require "action_view/helpers/tag_helper"
@@ -12,12 +14,12 @@ require "active_support/core_ext/string/inflections"
12
14
 
13
15
  module ActionView
14
16
  # = Action View Form Helpers
15
- module Helpers
17
+ module Helpers #:nodoc:
16
18
  # Form helpers are designed to make working with resources much easier
17
19
  # compared to using vanilla HTML.
18
20
  #
19
21
  # Typically, a form designed to create or update a resource reflects the
20
- # identity of the resource in several ways: (i) the url that the form is
22
+ # identity of the resource in several ways: (i) the URL that the form is
21
23
  # sent to (the form element's +action+ attribute) should result in a request
22
24
  # being routed to the appropriate controller action (with the appropriate <tt>:id</tt>
23
25
  # parameter in the case of an existing resource), (ii) input fields should
@@ -164,7 +166,7 @@ module ActionView
164
166
  # So for example you may use a named route directly. When the model is
165
167
  # represented by a string or symbol, as in the example above, if the
166
168
  # <tt>:url</tt> option is not specified, by default the form will be
167
- # sent back to the current url (We will describe below an alternative
169
+ # sent back to the current URL (We will describe below an alternative
168
170
  # resource-oriented usage of +form_for+ in which the URL does not need
169
171
  # to be specified explicitly).
170
172
  # * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
@@ -201,9 +203,9 @@ module ActionView
201
203
  # <%= f.submit %>
202
204
  # <% end %>
203
205
  #
204
- # This also works for the methods in FormOptionHelper and DateHelper that
206
+ # This also works for the methods in FormOptionsHelper and DateHelper that
205
207
  # are designed to work with an object as base, like
206
- # FormOptionHelper#collection_select and DateHelper#datetime_select.
208
+ # FormOptionsHelper#collection_select and DateHelper#datetime_select.
207
209
  #
208
210
  # === #form_for with a model object
209
211
  #
@@ -416,13 +418,13 @@ module ActionView
416
418
  #
417
419
  # To set an authenticity token you need to pass an <tt>:authenticity_token</tt> parameter
418
420
  #
419
- # <%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f|
421
+ # <%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f| %>
420
422
  # ...
421
423
  # <% end %>
422
424
  #
423
425
  # If you don't want to an authenticity token field be rendered at all just pass <tt>false</tt>:
424
426
  #
425
- # <%= form_for @invoice, url: external_url, authenticity_token: false do |f|
427
+ # <%= form_for @invoice, url: external_url, authenticity_token: false do |f| %>
426
428
  # ...
427
429
  # <% end %>
428
430
  def form_for(record, options = {}, &block)
@@ -474,7 +476,9 @@ module ActionView
474
476
  end
475
477
  private :apply_form_for_options!
476
478
 
477
- mattr_accessor(:form_with_generates_remote_forms) { true }
479
+ mattr_accessor :form_with_generates_remote_forms, default: true
480
+
481
+ mattr_accessor :form_with_generates_ids, default: false
478
482
 
479
483
  # Creates a form tag based on mixing URLs, scopes, or models.
480
484
  #
@@ -604,7 +608,7 @@ module ActionView
604
608
  # This is helpful when fragment-caching the form. Remote forms
605
609
  # get the authenticity token from the <tt>meta</tt> tag, so embedding is
606
610
  # unnecessary unless you support browsers without JavaScript.
607
- # * <tt>:local</tt> - By default form submits are remote and unobstrusive XHRs.
611
+ # * <tt>:local</tt> - By default form submits are remote and unobtrusive XHRs.
608
612
  # Disable remote submits with <tt>local: true</tt>.
609
613
  # * <tt>:skip_enforcing_utf8</tt> - By default a hidden field named +utf8+
610
614
  # is output to enforce UTF-8 submits. Set to true to skip the field.
@@ -638,16 +642,6 @@ module ActionView
638
642
  #
639
643
  # Where <tt>@document = Document.find(params[:id])</tt>.
640
644
  #
641
- # When using labels +form_with+ requires setting the id on the field being
642
- # labelled:
643
- #
644
- # <%= form_with(model: @post) do |form| %>
645
- # <%= form.label :title %>
646
- # <%= form.text_field :title, id: :post_title %>
647
- # <% end %>
648
- #
649
- # See +label+ for more on how the +for+ attribute is derived.
650
- #
651
645
  # === Mixing with other form helpers
652
646
  #
653
647
  # While +form_with+ uses a FormBuilder object it's possible to mix and
@@ -664,9 +658,9 @@ module ActionView
664
658
  # <%= form.submit %>
665
659
  # <% end %>
666
660
  #
667
- # Same goes for the methods in FormOptionHelper and DateHelper designed
661
+ # Same goes for the methods in FormOptionsHelper and DateHelper designed
668
662
  # to work with an object as a base, like
669
- # FormOptionHelper#collection_select and DateHelper#datetime_select.
663
+ # FormOptionsHelper#collection_select and DateHelper#datetime_select.
670
664
  #
671
665
  # === Setting the method
672
666
  #
@@ -742,9 +736,9 @@ module ActionView
742
736
  # def labelled_form_with(**options, &block)
743
737
  # form_with(**options.merge(builder: LabellingFormBuilder), &block)
744
738
  # end
745
- def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
739
+ def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
746
740
  options[:allow_method_names_outside_object] = true
747
- options[:skip_default_ids] = true
741
+ options[:skip_default_ids] = !form_with_generates_ids
748
742
 
749
743
  if model
750
744
  url ||= polymorphic_path(model, format: format)
@@ -755,7 +749,7 @@ module ActionView
755
749
 
756
750
  if block_given?
757
751
  builder = instantiate_builder(scope, model, options)
758
- output = capture(builder, &Proc.new)
752
+ output = capture(builder, &block)
759
753
  options[:multipart] ||= builder.multipart?
760
754
 
761
755
  html_options = html_options_for_form_with(url, model, options)
@@ -823,9 +817,9 @@ module ActionView
823
817
  # _class_ of the model object, e.g. if <tt>@person.permission</tt>, is
824
818
  # of class +Permission+, the field will still be named <tt>permission[admin]</tt>.
825
819
  #
826
- # Note: This also works for the methods in FormOptionHelper and
820
+ # Note: This also works for the methods in FormOptionsHelper and
827
821
  # DateHelper that are designed to work with an object as base, like
828
- # FormOptionHelper#collection_select and DateHelper#datetime_select.
822
+ # FormOptionsHelper#collection_select and DateHelper#datetime_select.
829
823
  #
830
824
  # === Nested Attributes Examples
831
825
  #
@@ -1020,14 +1014,13 @@ module ActionView
1020
1014
  # <%= fields :comment do |fields| %>
1021
1015
  # <%= fields.text_field :body %>
1022
1016
  # <% end %>
1023
- # # => <input type="text" name="comment[body]>
1017
+ # # => <input type="text" name="comment[body]">
1024
1018
  #
1025
1019
  # # Using a model infers the scope and assigns field values:
1026
- # <%= fields model: Comment.new(body: "full bodied") do |fields| %<
1020
+ # <%= fields model: Comment.new(body: "full bodied") do |fields| %>
1027
1021
  # <%= fields.text_field :body %>
1028
1022
  # <% end %>
1029
- # # =>
1030
- # <input type="text" name="comment[body] value="full bodied">
1023
+ # # => <input type="text" name="comment[body]" value="full bodied">
1031
1024
  #
1032
1025
  # # Using +fields+ with +form_with+:
1033
1026
  # <%= form_with model: @post do |form| %>
@@ -1042,16 +1035,6 @@ module ActionView
1042
1035
  # or model is yielded, so any generated field names are prefixed with
1043
1036
  # either the passed scope or the scope inferred from the <tt>:model</tt>.
1044
1037
  #
1045
- # When using labels +fields+ requires setting the id on the field being
1046
- # labelled:
1047
- #
1048
- # <%= fields :comment do |fields| %>
1049
- # <%= fields.label :body %>
1050
- # <%= fields.text_field :body, id: :comment_body %>
1051
- # <% end %>
1052
- #
1053
- # See +label+ for more on how the +for+ attribute is derived.
1054
- #
1055
1038
  # === Mixing with other form helpers
1056
1039
  #
1057
1040
  # While +form_with+ uses a FormBuilder object it's possible to mix and
@@ -1065,12 +1048,12 @@ module ActionView
1065
1048
  # <%= check_box_tag "comment[all_caps]", "1", @comment.commenter.hulk_mode? %>
1066
1049
  # <% end %>
1067
1050
  #
1068
- # Same goes for the methods in FormOptionHelper and DateHelper designed
1051
+ # Same goes for the methods in FormOptionsHelper and DateHelper designed
1069
1052
  # to work with an object as a base, like
1070
- # FormOptionHelper#collection_select and DateHelper#datetime_select.
1053
+ # FormOptionsHelper#collection_select and DateHelper#datetime_select.
1071
1054
  def fields(scope = nil, model: nil, **options, &block)
1072
1055
  options[:allow_method_names_outside_object] = true
1073
- options[:skip_default_ids] = true
1056
+ options[:skip_default_ids] = !form_with_generates_ids
1074
1057
 
1075
1058
  if model
1076
1059
  scope ||= model_name_from_record_or_class(model).param_key
@@ -1221,7 +1204,7 @@ module ActionView
1221
1204
  # file_field(:attachment, :file, class: 'file_input')
1222
1205
  # # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
1223
1206
  def file_field(object_name, method, options = {})
1224
- Tags::FileField.new(object_name, method, self, options).render
1207
+ Tags::FileField.new(object_name, method, self, convert_direct_upload_option_to_url(options.dup)).render
1225
1208
  end
1226
1209
 
1227
1210
  # Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
@@ -1597,7 +1580,7 @@ module ActionView
1597
1580
  # In the above block, a +FormBuilder+ object is yielded as the
1598
1581
  # +person_form+ variable. This allows you to generate the +text_field+
1599
1582
  # and +check_box+ fields by specifying their eponymous methods, which
1600
- # modify the underlying template and associates the +@person+ model object
1583
+ # modify the underlying template and associates the <tt>@person</tt> model object
1601
1584
  # with the form.
1602
1585
  #
1603
1586
  # The +FormBuilder+ object can be thought of as serving as a proxy for the
@@ -1636,14 +1619,15 @@ module ActionView
1636
1619
  include ModelNaming
1637
1620
 
1638
1621
  # The methods which wrap a form helper call.
1639
- class_attribute :field_helpers
1640
- self.field_helpers = [:fields_for, :fields, :label, :text_field, :password_field,
1641
- :hidden_field, :file_field, :text_area, :check_box,
1642
- :radio_button, :color_field, :search_field,
1643
- :telephone_field, :phone_field, :date_field,
1644
- :time_field, :datetime_field, :datetime_local_field,
1645
- :month_field, :week_field, :url_field, :email_field,
1646
- :number_field, :range_field]
1622
+ class_attribute :field_helpers, default: [
1623
+ :fields_for, :fields, :label, :text_field, :password_field,
1624
+ :hidden_field, :file_field, :text_area, :check_box,
1625
+ :radio_button, :color_field, :search_field,
1626
+ :telephone_field, :phone_field, :date_field,
1627
+ :time_field, :datetime_field, :datetime_local_field,
1628
+ :month_field, :week_field, :url_field, :email_field,
1629
+ :number_field, :range_field
1630
+ ]
1647
1631
 
1648
1632
  attr_accessor :object_name, :object, :options
1649
1633
 
@@ -1674,6 +1658,7 @@ module ActionView
1674
1658
  @nested_child_index = {}
1675
1659
  @object_name, @object, @template, @options = object_name, object, template, options
1676
1660
  @default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {}
1661
+ @default_html_options = @default_options.except(:skip_default_ids, :allow_method_names_outside_object)
1677
1662
 
1678
1663
  convert_to_legacy_options(@options)
1679
1664
 
@@ -1758,9 +1743,9 @@ module ActionView
1758
1743
  # _class_ of the model object, e.g. if <tt>@person.permission</tt>, is
1759
1744
  # of class +Permission+, the field will still be named <tt>permission[admin]</tt>.
1760
1745
  #
1761
- # Note: This also works for the methods in FormOptionHelper and
1746
+ # Note: This also works for the methods in FormOptionsHelper and
1762
1747
  # DateHelper that are designed to work with an object as base, like
1763
- # FormOptionHelper#collection_select and DateHelper#datetime_select.
1748
+ # FormOptionsHelper#collection_select and DateHelper#datetime_select.
1764
1749
  #
1765
1750
  # === Nested Attributes Examples
1766
1751
  #
@@ -1982,11 +1967,11 @@ module ActionView
1982
1967
  # See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
1983
1968
  def fields(scope = nil, model: nil, **options, &block)
1984
1969
  options[:allow_method_names_outside_object] = true
1985
- options[:skip_default_ids] = true
1970
+ options[:skip_default_ids] = !FormHelper.form_with_generates_ids
1986
1971
 
1987
1972
  convert_to_legacy_options(options)
1988
1973
 
1989
- fields_for(scope || model, model, **options, &block)
1974
+ fields_for(scope || model, model, options, &block)
1990
1975
  end
1991
1976
 
1992
1977
  # Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
@@ -2192,11 +2177,11 @@ module ActionView
2192
2177
  # <%= f.submit %>
2193
2178
  # <% end %>
2194
2179
  #
2195
- # In the example above, if @post is a new record, it will use "Create Post" as
2196
- # submit button label, otherwise, it uses "Update Post".
2180
+ # In the example above, if <tt>@post</tt> is a new record, it will use "Create Post" as
2181
+ # submit button label; otherwise, it uses "Update Post".
2197
2182
  #
2198
- # Those labels can be customized using I18n, under the helpers.submit key and accept
2199
- # the %{model} as translation interpolation:
2183
+ # Those labels can be customized using I18n under the +helpers.submit+ key and using
2184
+ # <tt>%{model}</tt> for translation interpolation:
2200
2185
  #
2201
2186
  # en:
2202
2187
  # helpers:
@@ -2204,7 +2189,7 @@ module ActionView
2204
2189
  # create: "Create a %{model}"
2205
2190
  # update: "Confirm changes to %{model}"
2206
2191
  #
2207
- # It also searches for a key specific for the given object:
2192
+ # It also searches for a key specific to the given object:
2208
2193
  #
2209
2194
  # en:
2210
2195
  # helpers:
@@ -2225,11 +2210,11 @@ module ActionView
2225
2210
  # <%= f.button %>
2226
2211
  # <% end %>
2227
2212
  #
2228
- # In the example above, if @post is a new record, it will use "Create Post" as
2229
- # button label, otherwise, it uses "Update Post".
2213
+ # In the example above, if <tt>@post</tt> is a new record, it will use "Create Post" as
2214
+ # button label; otherwise, it uses "Update Post".
2230
2215
  #
2231
- # Those labels can be customized using I18n, under the helpers.submit key
2232
- # (the same as submit helper) and accept the %{model} as translation interpolation:
2216
+ # Those labels can be customized using I18n under the +helpers.submit+ key
2217
+ # (the same as submit helper) and using <tt>%{model}</tt> for translation interpolation:
2233
2218
  #
2234
2219
  # en:
2235
2220
  # helpers:
@@ -2237,7 +2222,7 @@ module ActionView
2237
2222
  # create: "Create a %{model}"
2238
2223
  # update: "Confirm changes to %{model}"
2239
2224
  #
2240
- # It also searches for a key specific for the given object:
2225
+ # It also searches for a key specific to the given object:
2241
2226
  #
2242
2227
  # en:
2243
2228
  # helpers:
@@ -2347,8 +2332,6 @@ module ActionView
2347
2332
  end
2348
2333
 
2349
2334
  ActiveSupport.on_load(:action_view) do
2350
- cattr_accessor(:default_form_builder, instance_writer: false, instance_reader: false) do
2351
- ::ActionView::Helpers::FormBuilder
2352
- end
2335
+ cattr_accessor :default_form_builder, instance_writer: false, instance_reader: false, default: ::ActionView::Helpers::FormBuilder
2353
2336
  end
2354
2337
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "cgi"
2
4
  require "erb"
3
5
  require "action_view/helpers/form_helper"
@@ -7,7 +9,7 @@ require "active_support/core_ext/array/wrap"
7
9
 
8
10
  module ActionView
9
11
  # = Action View Form Option Helpers
10
- module Helpers
12
+ module Helpers #:nodoc:
11
13
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
12
14
  #
13
15
  # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
@@ -212,9 +214,13 @@ module ActionView
212
214
  # * +method+ - The attribute of +object+ corresponding to the select tag
213
215
  # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
214
216
  # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
215
- # array of child objects representing the <tt><option></tt> tags.
217
+ # array of child objects representing the <tt><option></tt> tags. It can also be any object that responds
218
+ # to +call+, such as a +proc+, that will be called for each member of the +collection+ to retrieve the
219
+ # value.
216
220
  # * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
217
- # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
221
+ # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag. It can also be any object
222
+ # that responds to +call+, such as a +proc+, that will be called for each member of the +collection+ to
223
+ # retrieve the label.
218
224
  # * +option_key_method+ - The name of a method which, when called on a child object of a member of
219
225
  # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
220
226
  # * +option_value_method+ - The name of a method which, when called on a child object of a member of
@@ -277,17 +283,17 @@ module ActionView
277
283
  # Finally, this method supports a <tt>:default</tt> option, which selects
278
284
  # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
279
285
  #
280
- # time_zone_select( "user", "time_zone", nil, include_blank: true)
286
+ # time_zone_select("user", "time_zone", nil, include_blank: true)
281
287
  #
282
- # time_zone_select( "user", "time_zone", nil, default: "Pacific Time (US & Canada)" )
288
+ # time_zone_select("user", "time_zone", nil, default: "Pacific Time (US & Canada)")
283
289
  #
284
- # time_zone_select( "user", 'time_zone', ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
290
+ # time_zone_select("user", 'time_zone', ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
285
291
  #
286
- # time_zone_select( "user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
292
+ # time_zone_select("user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
287
293
  #
288
- # time_zone_select( "user", 'time_zone', /Australia/)
294
+ # time_zone_select("user", 'time_zone', /Australia/)
289
295
  #
290
- # time_zone_select( "user", "time_zone", ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
296
+ # time_zone_select("user", "time_zone", ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
291
297
  def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
292
298
  Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
293
299
  end
@@ -455,9 +461,9 @@ module ActionView
455
461
  def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
456
462
  collection.map do |group|
457
463
  option_tags = options_from_collection_for_select(
458
- group.send(group_method), option_key_method, option_value_method, selected_key)
464
+ value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
459
465
 
460
- content_tag("optgroup".freeze, option_tags, label: group.send(group_label_method))
466
+ content_tag("optgroup".freeze, option_tags, label: value_for_collection(group, group_label_method))
461
467
  end.join.html_safe
462
468
  end
463
469
 
@@ -814,7 +820,7 @@ module ActionView
814
820
  #
815
821
  # Please refer to the documentation of the base helper for details.
816
822
  def select(method, choices = nil, options = {}, html_options = {}, &block)
817
- @template.select(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options), &block)
823
+ @template.select(@object_name, method, choices, objectify_options(options), @default_html_options.merge(html_options), &block)
818
824
  end
819
825
 
820
826
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_select for form builders:
@@ -826,7 +832,7 @@ module ActionView
826
832
  #
827
833
  # Please refer to the documentation of the base helper for details.
828
834
  def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
829
- @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
835
+ @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options))
830
836
  end
831
837
 
832
838
  # Wraps ActionView::Helpers::FormOptionsHelper#grouped_collection_select for form builders:
@@ -838,7 +844,7 @@ module ActionView
838
844
  #
839
845
  # Please refer to the documentation of the base helper for details.
840
846
  def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
841
- @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options))
847
+ @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_html_options.merge(html_options))
842
848
  end
843
849
 
844
850
  # Wraps ActionView::Helpers::FormOptionsHelper#time_zone_select for form builders:
@@ -850,7 +856,7 @@ module ActionView
850
856
  #
851
857
  # Please refer to the documentation of the base helper for details.
852
858
  def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
853
- @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
859
+ @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options))
854
860
  end
855
861
 
856
862
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
@@ -862,7 +868,7 @@ module ActionView
862
868
  #
863
869
  # Please refer to the documentation of the base helper for details.
864
870
  def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
865
- @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options), &block)
871
+ @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block)
866
872
  end
867
873
 
868
874
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_radio_buttons for form builders:
@@ -874,7 +880,7 @@ module ActionView
874
880
  #
875
881
  # Please refer to the documentation of the base helper for details.
876
882
  def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
877
- @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options), &block)
883
+ @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block)
878
884
  end
879
885
  end
880
886
  end