actionview 5.2.7.1 → 6.1.4.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +250 -112
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -3
  5. data/lib/action_view/base.rb +81 -15
  6. data/lib/action_view/buffers.rb +15 -0
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +5 -9
  9. data/lib/action_view/dependency_tracker.rb +10 -4
  10. data/lib/action_view/digestor.rb +15 -22
  11. data/lib/action_view/flows.rb +0 -1
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +64 -47
  15. data/lib/action_view/helpers/asset_url_helper.rb +9 -6
  16. data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
  17. data/lib/action_view/helpers/cache_helper.rb +23 -22
  18. data/lib/action_view/helpers/capture_helper.rb +4 -0
  19. data/lib/action_view/helpers/csp_helper.rb +4 -2
  20. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  21. data/lib/action_view/helpers/date_helper.rb +73 -30
  22. data/lib/action_view/helpers/form_helper.rb +305 -37
  23. data/lib/action_view/helpers/form_options_helper.rb +23 -23
  24. data/lib/action_view/helpers/form_tag_helper.rb +19 -16
  25. data/lib/action_view/helpers/javascript_helper.rb +12 -11
  26. data/lib/action_view/helpers/number_helper.rb +14 -8
  27. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  28. data/lib/action_view/helpers/rendering_helper.rb +17 -7
  29. data/lib/action_view/helpers/sanitize_helper.rb +12 -18
  30. data/lib/action_view/helpers/tag_helper.rb +100 -55
  31. data/lib/action_view/helpers/tags/base.rb +18 -11
  32. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  33. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  34. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  35. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  36. data/lib/action_view/helpers/tags/color_field.rb +1 -2
  37. data/lib/action_view/helpers/tags/date_field.rb +1 -2
  38. data/lib/action_view/helpers/tags/date_select.rb +2 -3
  39. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  40. data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
  41. data/lib/action_view/helpers/tags/label.rb +4 -1
  42. data/lib/action_view/helpers/tags/month_field.rb +1 -2
  43. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  44. data/lib/action_view/helpers/tags/select.rb +1 -2
  45. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  46. data/lib/action_view/helpers/tags/time_field.rb +1 -2
  47. data/lib/action_view/helpers/tags/translator.rb +1 -6
  48. data/lib/action_view/helpers/tags/week_field.rb +1 -2
  49. data/lib/action_view/helpers/text_helper.rb +4 -5
  50. data/lib/action_view/helpers/translation_helper.rb +94 -54
  51. data/lib/action_view/helpers/url_helper.rb +136 -28
  52. data/lib/action_view/helpers.rb +0 -2
  53. data/lib/action_view/layouts.rb +8 -10
  54. data/lib/action_view/log_subscriber.rb +30 -15
  55. data/lib/action_view/lookup_context.rb +63 -35
  56. data/lib/action_view/path_set.rb +3 -12
  57. data/lib/action_view/railtie.rb +42 -26
  58. data/lib/action_view/record_identifier.rb +2 -3
  59. data/lib/action_view/renderer/abstract_renderer.rb +142 -11
  60. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  61. data/lib/action_view/renderer/object_renderer.rb +34 -0
  62. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +61 -16
  63. data/lib/action_view/renderer/partial_renderer.rb +21 -273
  64. data/lib/action_view/renderer/renderer.rb +59 -4
  65. data/lib/action_view/renderer/streaming_template_renderer.rb +10 -8
  66. data/lib/action_view/renderer/template_renderer.rb +35 -27
  67. data/lib/action_view/rendering.rb +54 -33
  68. data/lib/action_view/routing_url_for.rb +13 -12
  69. data/lib/action_view/template/error.rb +30 -15
  70. data/lib/action_view/template/handlers/builder.rb +2 -2
  71. data/lib/action_view/template/handlers/erb/erubi.rb +15 -9
  72. data/lib/action_view/template/handlers/erb.rb +16 -11
  73. data/lib/action_view/template/handlers/html.rb +1 -1
  74. data/lib/action_view/template/handlers/raw.rb +2 -2
  75. data/lib/action_view/template/handlers.rb +1 -1
  76. data/lib/action_view/template/html.rb +5 -6
  77. data/lib/action_view/template/inline.rb +22 -0
  78. data/lib/action_view/template/raw_file.rb +25 -0
  79. data/lib/action_view/template/renderable.rb +24 -0
  80. data/lib/action_view/template/resolver.rb +191 -150
  81. data/lib/action_view/template/sources/file.rb +17 -0
  82. data/lib/action_view/template/sources.rb +13 -0
  83. data/lib/action_view/template/text.rb +2 -3
  84. data/lib/action_view/template.rb +66 -75
  85. data/lib/action_view/test_case.rb +21 -29
  86. data/lib/action_view/testing/resolvers.rb +18 -27
  87. data/lib/action_view/unbound_template.rb +31 -0
  88. data/lib/action_view/view_paths.rb +59 -38
  89. data/lib/action_view.rb +7 -2
  90. data/lib/assets/compiled/rails-ujs.js +32 -6
  91. metadata +29 -18
  92. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -11,6 +11,7 @@ require "active_support/core_ext/module/attribute_accessors"
11
11
  require "active_support/core_ext/hash/slice"
12
12
  require "active_support/core_ext/string/output_safety"
13
13
  require "active_support/core_ext/string/inflections"
14
+ require "active_support/core_ext/symbol/starts_ends_with"
14
15
 
15
16
  module ActionView
16
17
  # = Action View Form Helpers
@@ -185,8 +186,7 @@ module ActionView
185
186
  # get the authenticity token from the <tt>meta</tt> tag, so embedding is
186
187
  # unnecessary unless you support browsers without JavaScript.
187
188
  # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive
188
- # JavaScript drivers to control the submit behavior. By default this
189
- # behavior is an ajax submit.
189
+ # JavaScript drivers to control the submit behavior.
190
190
  # * <tt>:enforce_utf8</tt> - If set to false, a hidden input with name
191
191
  # utf8 is not output.
192
192
  # * <tt>:html</tt> - Optional HTML attributes for the form tag.
@@ -322,10 +322,8 @@ module ActionView
322
322
  # remote: true
323
323
  #
324
324
  # in the options hash creates a form that will allow the unobtrusive JavaScript drivers to modify its
325
- # behavior. The expected default behavior is an XMLHttpRequest in the background instead of the regular
326
- # POST arrangement, but ultimately the behavior is the choice of the JavaScript driver implementor.
327
- # Even though it's using JavaScript to serialize the form elements, the form submission will work just like
328
- # a regular submission as viewed by the receiving side (all elements available in <tt>params</tt>).
325
+ # behavior. The form submission will work just like a regular submission as viewed by the receiving
326
+ # side (all elements available in <tt>params</tt>).
329
327
  #
330
328
  # Example:
331
329
  #
@@ -535,11 +533,6 @@ module ActionView
535
533
  # accessible as <tt>params[:title]</tt> and <tt>params[:post][:title]</tt>
536
534
  # respectively.
537
535
  #
538
- # By default +form_with+ attaches the <tt>data-remote</tt> attribute
539
- # submitting the form via an XMLHTTPRequest in the background if an
540
- # Unobtrusive JavaScript driver, like rails-ujs, is used. See the
541
- # <tt>:local</tt> option for more.
542
- #
543
536
  # For ease of comparison the examples above left out the submit button,
544
537
  # as well as the auto generated hidden fields that enable UTF-8 support
545
538
  # and adds an authenticity token needed for cross site request forgery
@@ -590,6 +583,9 @@ module ActionView
590
583
  # Skipped if a <tt>:url</tt> is passed.
591
584
  # * <tt>:scope</tt> - The scope to prefix input field names with and
592
585
  # thereby how the submitted parameters are grouped in controllers.
586
+ # * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
587
+ # id attributes on form elements. The namespace attribute will be prefixed
588
+ # with underscore on the generated HTML id.
593
589
  # * <tt>:model</tt> - A model object to infer the <tt>:url</tt> and
594
590
  # <tt>:scope</tt> by, plus fill out input field values.
595
591
  # So if a +title+ attribute is set to "Ahoy!" then a +title+ input
@@ -608,10 +604,12 @@ module ActionView
608
604
  # This is helpful when fragment-caching the form. Remote forms
609
605
  # get the authenticity token from the <tt>meta</tt> tag, so embedding is
610
606
  # unnecessary unless you support browsers without JavaScript.
611
- # * <tt>:local</tt> - By default form submits are remote and unobtrusive XHRs.
612
- # Disable remote submits with <tt>local: true</tt>.
613
- # * <tt>:skip_enforcing_utf8</tt> - By default a hidden field named +utf8+
614
- # is output to enforce UTF-8 submits. Set to true to skip the field.
607
+ # * <tt>:local</tt> - By default form submits via typical HTTP requests.
608
+ # Enable remote and unobtrusive XHRs submits with <tt>local: false</tt>.
609
+ # Remote forms may be enabled by default by setting
610
+ # <tt>config.action_view.form_with_generates_remote_forms = true</tt>.
611
+ # * <tt>:skip_enforcing_utf8</tt> - If set to true, a hidden input with name
612
+ # utf8 is not output.
615
613
  # * <tt>:builder</tt> - Override the object used to build the form.
616
614
  # * <tt>:id</tt> - Optional HTML id attribute.
617
615
  # * <tt>:class</tt> - Optional HTML class attribute.
@@ -752,10 +750,10 @@ module ActionView
752
750
  output = capture(builder, &block)
753
751
  options[:multipart] ||= builder.multipart?
754
752
 
755
- html_options = html_options_for_form_with(url, model, options)
753
+ html_options = html_options_for_form_with(url, model, **options)
756
754
  form_tag_with_body(html_options, output)
757
755
  else
758
- html_options = html_options_for_form_with(url, model, options)
756
+ html_options = html_options_for_form_with(url, model, **options)
759
757
  form_tag_html(html_options)
760
758
  end
761
759
  end
@@ -885,7 +883,7 @@ module ActionView
885
883
  #
886
884
  # Now, when you use a form element with the <tt>_destroy</tt> parameter,
887
885
  # with a value that evaluates to +true+, you will destroy the associated
888
- # model (eg. 1, '1', true, or 'true'):
886
+ # model (e.g. 1, '1', true, or 'true'):
889
887
  #
890
888
  # <%= form_for @person do |person_form| %>
891
889
  # ...
@@ -974,7 +972,7 @@ module ActionView
974
972
  # This will allow you to specify which models to destroy in the
975
973
  # attributes hash by adding a form element for the <tt>_destroy</tt>
976
974
  # parameter with a value that evaluates to +true+
977
- # (eg. 1, '1', true, or 'true'):
975
+ # (e.g. 1, '1', true, or 'true'):
978
976
  #
979
977
  # <%= form_for @person do |person_form| %>
980
978
  # ...
@@ -1107,6 +1105,16 @@ module ActionView
1107
1105
  # label(:post, :privacy, "Public Post", value: "public")
1108
1106
  # # => <label for="post_privacy_public">Public Post</label>
1109
1107
  #
1108
+ # label(:post, :cost) do |translation|
1109
+ # content_tag(:span, translation, class: "cost_label")
1110
+ # end
1111
+ # # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
1112
+ #
1113
+ # label(:post, :cost) do |builder|
1114
+ # content_tag(:span, builder.translation, class: "cost_label")
1115
+ # end
1116
+ # # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
1117
+ #
1110
1118
  # label(:post, :terms) do
1111
1119
  # raw('Accept <a href="/terms">Terms</a>.')
1112
1120
  # end
@@ -1127,6 +1135,9 @@ module ActionView
1127
1135
  # text_field(:post, :title, class: "create_input")
1128
1136
  # # => <input type="text" id="post_title" name="post[title]" value="#{@post.title}" class="create_input" />
1129
1137
  #
1138
+ # text_field(:post, :title, maxlength: 30, class: "title_input")
1139
+ # # => <input type="text" id="post_title" name="post[title]" maxlength="30" size="30" value="#{@post.title}" class="title_input" />
1140
+ #
1130
1141
  # text_field(:session, :user, onchange: "if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }")
1131
1142
  # # => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange="if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }"/>
1132
1143
  #
@@ -1519,10 +1530,10 @@ module ActionView
1519
1530
 
1520
1531
  private
1521
1532
  def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,
1522
- skip_enforcing_utf8: false, **options)
1533
+ skip_enforcing_utf8: nil, **options)
1523
1534
  html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
1524
1535
  html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
1525
- html_options[:enforce_utf8] = !skip_enforcing_utf8
1536
+ html_options[:enforce_utf8] = !skip_enforcing_utf8 unless skip_enforcing_utf8.nil?
1526
1537
 
1527
1538
  html_options[:enctype] = "multipart/form-data" if html_options.delete(:multipart)
1528
1539
 
@@ -1662,8 +1673,8 @@ module ActionView
1662
1673
 
1663
1674
  convert_to_legacy_options(@options)
1664
1675
 
1665
- if @object_name.to_s.match(/\[\]$/)
1666
- if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
1676
+ if @object_name&.end_with?("[]")
1677
+ if (object ||= @template.instance_variable_get("@#{@object_name[0..-3]}")) && object.respond_to?(:to_param)
1667
1678
  @auto_index = object.to_param
1668
1679
  else
1669
1680
  raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
@@ -1674,11 +1685,232 @@ module ActionView
1674
1685
  @index = options[:index] || options[:child_index]
1675
1686
  end
1676
1687
 
1688
+ ##
1689
+ # :method: text_field
1690
+ #
1691
+ # :call-seq: text_field(method, options = {})
1692
+ #
1693
+ # Wraps ActionView::Helpers::FormHelper#text_field for form builders:
1694
+ #
1695
+ # <%= form_with model: @user do |f| %>
1696
+ # <%= f.text_field :name %>
1697
+ # <% end %>
1698
+ #
1699
+ # Please refer to the documentation of the base helper for details.
1700
+
1701
+ ##
1702
+ # :method: password_field
1703
+ #
1704
+ # :call-seq: password_field(method, options = {})
1705
+ #
1706
+ # Wraps ActionView::Helpers::FormHelper#password_field for form builders:
1707
+ #
1708
+ # <%= form_with model: @user do |f| %>
1709
+ # <%= f.password_field :password %>
1710
+ # <% end %>
1711
+ #
1712
+ # Please refer to the documentation of the base helper for details.
1713
+
1714
+ ##
1715
+ # :method: text_area
1716
+ #
1717
+ # :call-seq: text_area(method, options = {})
1718
+ #
1719
+ # Wraps ActionView::Helpers::FormHelper#text_area for form builders:
1720
+ #
1721
+ # <%= form_with model: @user do |f| %>
1722
+ # <%= f.text_area :detail %>
1723
+ # <% end %>
1724
+ #
1725
+ # Please refer to the documentation of the base helper for details.
1726
+
1727
+ ##
1728
+ # :method: color_field
1729
+ #
1730
+ # :call-seq: color_field(method, options = {})
1731
+ #
1732
+ # Wraps ActionView::Helpers::FormHelper#color_field for form builders:
1733
+ #
1734
+ # <%= form_with model: @user do |f| %>
1735
+ # <%= f.color_field :favorite_color %>
1736
+ # <% end %>
1737
+ #
1738
+ # Please refer to the documentation of the base helper for details.
1739
+
1740
+ ##
1741
+ # :method: search_field
1742
+ #
1743
+ # :call-seq: search_field(method, options = {})
1744
+ #
1745
+ # Wraps ActionView::Helpers::FormHelper#search_field for form builders:
1746
+ #
1747
+ # <%= form_with model: @user do |f| %>
1748
+ # <%= f.search_field :name %>
1749
+ # <% end %>
1750
+ #
1751
+ # Please refer to the documentation of the base helper for details.
1752
+
1753
+ ##
1754
+ # :method: telephone_field
1755
+ #
1756
+ # :call-seq: telephone_field(method, options = {})
1757
+ #
1758
+ # Wraps ActionView::Helpers::FormHelper#telephone_field for form builders:
1759
+ #
1760
+ # <%= form_with model: @user do |f| %>
1761
+ # <%= f.telephone_field :phone %>
1762
+ # <% end %>
1763
+ #
1764
+ # Please refer to the documentation of the base helper for details.
1765
+
1766
+ ##
1767
+ # :method: phone_field
1768
+ #
1769
+ # :call-seq: phone_field(method, options = {})
1770
+ #
1771
+ # Wraps ActionView::Helpers::FormHelper#phone_field for form builders:
1772
+ #
1773
+ # <%= form_with model: @user do |f| %>
1774
+ # <%= f.phone_field :phone %>
1775
+ # <% end %>
1776
+ #
1777
+ # Please refer to the documentation of the base helper for details.
1778
+
1779
+ ##
1780
+ # :method: date_field
1781
+ #
1782
+ # :call-seq: date_field(method, options = {})
1783
+ #
1784
+ # Wraps ActionView::Helpers::FormHelper#date_field for form builders:
1785
+ #
1786
+ # <%= form_with model: @user do |f| %>
1787
+ # <%= f.date_field :born_on %>
1788
+ # <% end %>
1789
+ #
1790
+ # Please refer to the documentation of the base helper for details.
1791
+
1792
+ ##
1793
+ # :method: time_field
1794
+ #
1795
+ # :call-seq: time_field(method, options = {})
1796
+ #
1797
+ # Wraps ActionView::Helpers::FormHelper#time_field for form builders:
1798
+ #
1799
+ # <%= form_with model: @user do |f| %>
1800
+ # <%= f.time_field :born_at %>
1801
+ # <% end %>
1802
+ #
1803
+ # Please refer to the documentation of the base helper for details.
1804
+
1805
+ ##
1806
+ # :method: datetime_field
1807
+ #
1808
+ # :call-seq: datetime_field(method, options = {})
1809
+ #
1810
+ # Wraps ActionView::Helpers::FormHelper#datetime_field for form builders:
1811
+ #
1812
+ # <%= form_with model: @user do |f| %>
1813
+ # <%= f.datetime_field :graduation_day %>
1814
+ # <% end %>
1815
+ #
1816
+ # Please refer to the documentation of the base helper for details.
1817
+
1818
+ ##
1819
+ # :method: datetime_local_field
1820
+ #
1821
+ # :call-seq: datetime_local_field(method, options = {})
1822
+ #
1823
+ # Wraps ActionView::Helpers::FormHelper#datetime_local_field for form builders:
1824
+ #
1825
+ # <%= form_with model: @user do |f| %>
1826
+ # <%= f.datetime_local_field :graduation_day %>
1827
+ # <% end %>
1828
+ #
1829
+ # Please refer to the documentation of the base helper for details.
1830
+
1831
+ ##
1832
+ # :method: month_field
1833
+ #
1834
+ # :call-seq: month_field(method, options = {})
1835
+ #
1836
+ # Wraps ActionView::Helpers::FormHelper#month_field for form builders:
1837
+ #
1838
+ # <%= form_with model: @user do |f| %>
1839
+ # <%= f.month_field :birthday_month %>
1840
+ # <% end %>
1841
+ #
1842
+ # Please refer to the documentation of the base helper for details.
1843
+
1844
+ ##
1845
+ # :method: week_field
1846
+ #
1847
+ # :call-seq: week_field(method, options = {})
1848
+ #
1849
+ # Wraps ActionView::Helpers::FormHelper#week_field for form builders:
1850
+ #
1851
+ # <%= form_with model: @user do |f| %>
1852
+ # <%= f.week_field :birthday_week %>
1853
+ # <% end %>
1854
+ #
1855
+ # Please refer to the documentation of the base helper for details.
1856
+
1857
+ ##
1858
+ # :method: url_field
1859
+ #
1860
+ # :call-seq: url_field(method, options = {})
1861
+ #
1862
+ # Wraps ActionView::Helpers::FormHelper#url_field for form builders:
1863
+ #
1864
+ # <%= form_with model: @user do |f| %>
1865
+ # <%= f.url_field :homepage %>
1866
+ # <% end %>
1867
+ #
1868
+ # Please refer to the documentation of the base helper for details.
1869
+
1870
+ ##
1871
+ # :method: email_field
1872
+ #
1873
+ # :call-seq: email_field(method, options = {})
1874
+ #
1875
+ # Wraps ActionView::Helpers::FormHelper#email_field for form builders:
1876
+ #
1877
+ # <%= form_with model: @user do |f| %>
1878
+ # <%= f.email_field :address %>
1879
+ # <% end %>
1880
+ #
1881
+ # Please refer to the documentation of the base helper for details.
1882
+
1883
+ ##
1884
+ # :method: number_field
1885
+ #
1886
+ # :call-seq: number_field(method, options = {})
1887
+ #
1888
+ # Wraps ActionView::Helpers::FormHelper#number_field for form builders:
1889
+ #
1890
+ # <%= form_with model: @user do |f| %>
1891
+ # <%= f.number_field :age %>
1892
+ # <% end %>
1893
+ #
1894
+ # Please refer to the documentation of the base helper for details.
1895
+
1896
+ ##
1897
+ # :method: range_field
1898
+ #
1899
+ # :call-seq: range_field(method, options = {})
1900
+ #
1901
+ # Wraps ActionView::Helpers::FormHelper#range_field for form builders:
1902
+ #
1903
+ # <%= form_with model: @user do |f| %>
1904
+ # <%= f.range_field :age %>
1905
+ # <% end %>
1906
+ #
1907
+ # Please refer to the documentation of the base helper for details.
1908
+
1677
1909
  (field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
1678
1910
  class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
1679
1911
  def #{selector}(method, options = {}) # def text_field(method, options = {})
1680
- @template.send( # @template.send(
1681
- #{selector.inspect}, # "text_field",
1912
+ @template.public_send( # @template.public_send(
1913
+ #{selector.inspect}, # :text_field,
1682
1914
  @object_name, # @object_name,
1683
1915
  method, # method,
1684
1916
  objectify_options(options)) # objectify_options(options))
@@ -1811,7 +2043,7 @@ module ActionView
1811
2043
  #
1812
2044
  # Now, when you use a form element with the <tt>_destroy</tt> parameter,
1813
2045
  # with a value that evaluates to +true+, you will destroy the associated
1814
- # model (eg. 1, '1', true, or 'true'):
2046
+ # model (e.g. 1, '1', true, or 'true'):
1815
2047
  #
1816
2048
  # <%= form_for @person do |person_form| %>
1817
2049
  # ...
@@ -1900,7 +2132,7 @@ module ActionView
1900
2132
  # This will allow you to specify which models to destroy in the
1901
2133
  # attributes hash by adding a form element for the <tt>_destroy</tt>
1902
2134
  # parameter with a value that evaluates to +true+
1903
- # (eg. 1, '1', true, or 'true'):
2135
+ # (e.g. 1, '1', true, or 'true'):
1904
2136
  #
1905
2137
  # <%= form_for @person do |person_form| %>
1906
2138
  # ...
@@ -1947,15 +2179,14 @@ module ActionView
1947
2179
  index = if options.has_key?(:index)
1948
2180
  options[:index]
1949
2181
  elsif defined?(@auto_index)
1950
- object_name = object_name.to_s.sub(/\[\]$/, "")
2182
+ object_name = object_name.to_s.delete_suffix("[]")
1951
2183
  @auto_index
1952
2184
  end
1953
2185
 
1954
2186
  record_name = if index
1955
2187
  "#{object_name}[#{index}][#{record_name}]"
1956
- elsif record_name.to_s.end_with?("[]")
1957
- record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]")
1958
- "#{object_name}#{record_name}"
2188
+ elsif record_name.end_with?("[]")
2189
+ "#{object_name}[#{record_name[0..-3]}][#{record_object.id}]"
1959
2190
  else
1960
2191
  "#{object_name}[#{record_name}]"
1961
2192
  end
@@ -2018,6 +2249,24 @@ module ActionView
2018
2249
  # label(:privacy, "Public Post", value: "public")
2019
2250
  # # => <label for="post_privacy_public">Public Post</label>
2020
2251
  #
2252
+ # label(:cost) do |translation|
2253
+ # content_tag(:span, translation, class: "cost_label")
2254
+ # end
2255
+ # # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
2256
+ #
2257
+ # label(:cost) do |builder|
2258
+ # content_tag(:span, builder.translation, class: "cost_label")
2259
+ # end
2260
+ # # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
2261
+ #
2262
+ # label(:cost) do |builder|
2263
+ # content_tag(:span, builder.translation, class: [
2264
+ # "cost_label",
2265
+ # ("error_label" if builder.object.errors.include?(:cost))
2266
+ # ])
2267
+ # end
2268
+ # # => <label for="post_cost"><span class="cost_label error_label">Total cost</span></label>
2269
+ #
2021
2270
  # label(:terms) do
2022
2271
  # raw('Accept <a href="/terms">Terms</a>.')
2023
2272
  # end
@@ -2241,19 +2490,33 @@ module ActionView
2241
2490
  # # <strong>Ask me!</strong>
2242
2491
  # # </button>
2243
2492
  #
2493
+ # button do |text|
2494
+ # content_tag(:strong, text)
2495
+ # end
2496
+ # # => <button name='button' type='submit'>
2497
+ # # <strong>Create post</strong>
2498
+ # # </button>
2499
+ #
2244
2500
  def button(value = nil, options = {}, &block)
2245
2501
  value, options = nil, value if value.is_a?(Hash)
2246
2502
  value ||= submit_default_value
2247
- @template.button_tag(value, options, &block)
2503
+
2504
+ if block_given?
2505
+ value = @template.capture { yield(value) }
2506
+ end
2507
+
2508
+ @template.button_tag(value, options)
2248
2509
  end
2249
2510
 
2250
- def emitted_hidden_id?
2511
+ def emitted_hidden_id? # :nodoc:
2251
2512
  @emitted_hidden_id ||= nil
2252
2513
  end
2253
2514
 
2254
2515
  private
2255
2516
  def objectify_options(options)
2256
- @default_options.merge(options.merge(object: @object))
2517
+ result = @default_options.merge(options)
2518
+ result[:object] = @object
2519
+ result
2257
2520
  end
2258
2521
 
2259
2522
  def submit_default_value
@@ -2267,7 +2530,12 @@ module ActionView
2267
2530
  end
2268
2531
 
2269
2532
  defaults = []
2270
- defaults << :"helpers.submit.#{object_name}.#{key}"
2533
+ # Object is a model and it is not overwritten by as and scope option.
2534
+ if object.respond_to?(:model_name) && object_name.to_s == model.downcase
2535
+ defaults << :"helpers.submit.#{object.model_name.i18n_key}.#{key}"
2536
+ else
2537
+ defaults << :"helpers.submit.#{object_name}.#{key}"
2538
+ end
2271
2539
  defaults << :"helpers.submit.#{key}"
2272
2540
  defaults << "#{key.to_s.humanize} #{model}"
2273
2541
 
@@ -2283,9 +2551,9 @@ module ActionView
2283
2551
  association = convert_to_model(association)
2284
2552
 
2285
2553
  if association.respond_to?(:persisted?)
2286
- association = [association] if @object.send(association_name).respond_to?(:to_ary)
2554
+ association = [association] if @object.public_send(association_name).respond_to?(:to_ary)
2287
2555
  elsif !association.respond_to?(:to_ary)
2288
- association = @object.send(association_name)
2556
+ association = @object.public_send(association_name)
2289
2557
  end
2290
2558
 
2291
2559
  if association.respond_to?(:to_ary)
@@ -16,12 +16,12 @@ module ActionView
16
16
  #
17
17
  # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
18
18
  #
19
- # select("post", "category", Post::CATEGORIES, {include_blank: true})
19
+ # select("post", "category", Post::CATEGORIES, { include_blank: true })
20
20
  #
21
21
  # could become:
22
22
  #
23
23
  # <select name="post[category]" id="post_category">
24
- # <option value=""></option>
24
+ # <option value="" label=" "></option>
25
25
  # <option value="joke">joke</option>
26
26
  # <option value="poem">poem</option>
27
27
  # </select>
@@ -30,7 +30,7 @@ module ActionView
30
30
  #
31
31
  # Example with <tt>@post.person_id => 2</tt>:
32
32
  #
33
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {include_blank: 'None'})
33
+ # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: 'None' })
34
34
  #
35
35
  # could become:
36
36
  #
@@ -43,7 +43,7 @@ module ActionView
43
43
  #
44
44
  # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
45
45
  #
46
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {prompt: 'Select Person'})
46
+ # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { prompt: 'Select Person' })
47
47
  #
48
48
  # could become:
49
49
  #
@@ -69,12 +69,11 @@ module ActionView
69
69
  #
70
70
  # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
71
71
  #
72
- # select("post", "category", Post::CATEGORIES, {disabled: 'restricted'})
72
+ # select("post", "category", Post::CATEGORIES, { disabled: 'restricted' })
73
73
  #
74
74
  # could become:
75
75
  #
76
76
  # <select name="post[category]" id="post_category">
77
- # <option value=""></option>
78
77
  # <option value="joke">joke</option>
79
78
  # <option value="poem">poem</option>
80
79
  # <option disabled="disabled" value="restricted">restricted</option>
@@ -82,7 +81,7 @@ module ActionView
82
81
  #
83
82
  # When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
84
83
  #
85
- # collection_select(:post, :category_id, Category.all, :id, :name, {disabled: -> (category) { category.archived? }})
84
+ # collection_select(:post, :category_id, Category.all, :id, :name, { disabled: -> (category) { category.archived? } })
86
85
  #
87
86
  # If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
88
87
  # <select name="post[category_id]" id="post_category_id">
@@ -107,12 +106,12 @@ module ActionView
107
106
  #
108
107
  # For example:
109
108
  #
110
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { include_blank: true })
109
+ # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
111
110
  #
112
111
  # would become:
113
112
  #
114
113
  # <select name="post[person_id]" id="post_person_id">
115
- # <option value=""></option>
114
+ # <option value="" label=" "></option>
116
115
  # <option value="1" selected="selected">David</option>
117
116
  # <option value="2">Eileen</option>
118
117
  # <option value="3">Rafael</option>
@@ -143,7 +142,7 @@ module ActionView
143
142
  #
144
143
  # The HTML specification says when +multiple+ parameter passed to select and all options got deselected
145
144
  # web browsers do not send any value to server. Unfortunately this introduces a gotcha:
146
- # if an +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
145
+ # if a +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
147
146
  # the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
148
147
  # any mass-assignment idiom like
149
148
  #
@@ -323,12 +322,12 @@ module ActionView
323
322
  #
324
323
  # You can optionally provide HTML attributes as the last element of the array.
325
324
  #
326
- # options_for_select([ "Denmark", ["USA", {class: 'bold'}], "Sweden" ], ["USA", "Sweden"])
325
+ # options_for_select([ "Denmark", ["USA", { class: 'bold' }], "Sweden" ], ["USA", "Sweden"])
327
326
  # # => <option value="Denmark">Denmark</option>
328
327
  # # => <option value="USA" class="bold" selected="selected">USA</option>
329
328
  # # => <option value="Sweden" selected="selected">Sweden</option>
330
329
  #
331
- # options_for_select([["Dollar", "$", {class: "bold"}], ["Kroner", "DKK", {onclick: "alert('HI');"}]])
330
+ # options_for_select([["Dollar", "$", { class: "bold" }], ["Kroner", "DKK", { onclick: "alert('HI');" }]])
332
331
  # # => <option value="$" class="bold">Dollar</option>
333
332
  # # => <option value="DKK" onclick="alert('HI');">Kroner</option>
334
333
  #
@@ -463,7 +462,7 @@ module ActionView
463
462
  option_tags = options_from_collection_for_select(
464
463
  value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
465
464
 
466
- content_tag("optgroup".freeze, option_tags, label: value_for_collection(group, group_label_method))
465
+ content_tag("optgroup", option_tags, label: value_for_collection(group, group_label_method))
467
466
  end.join.html_safe
468
467
  end
469
468
 
@@ -535,7 +534,7 @@ module ActionView
535
534
  body = "".html_safe
536
535
 
537
536
  if prompt
538
- body.safe_concat content_tag("option".freeze, prompt_text(prompt), value: "")
537
+ body.safe_concat content_tag("option", prompt_text(prompt), value: "")
539
538
  end
540
539
 
541
540
  grouped_options.each do |container|
@@ -548,7 +547,7 @@ module ActionView
548
547
  end
549
548
 
550
549
  html_attributes = { label: label }.merge!(html_attributes)
551
- body.safe_concat content_tag("optgroup".freeze, options_for_select(container, selected_key), html_attributes)
550
+ body.safe_concat content_tag("optgroup", options_for_select(container, selected_key), html_attributes)
552
551
  end
553
552
 
554
553
  body
@@ -566,9 +565,10 @@ module ActionView
566
565
  # an ActiveSupport::TimeZone.
567
566
  #
568
567
  # By default, +model+ is the ActiveSupport::TimeZone constant (which can
569
- # be obtained in Active Record as a value object). The only requirement
570
- # is that the +model+ parameter be an object that responds to +all+, and
571
- # returns an array of objects that represent time zones.
568
+ # be obtained in Active Record as a value object). The +model+ parameter
569
+ # must respond to +all+ and return an array of objects that represent time
570
+ # zones; each object must respond to +name+. If a Regexp is given it will
571
+ # attempt to match the zones using <code>match?</code> method.
572
572
  #
573
573
  # NOTE: Only the option tags are returned, you have to wrap this call in
574
574
  # a regular HTML select tag.
@@ -580,11 +580,11 @@ module ActionView
580
580
 
581
581
  if priority_zones
582
582
  if priority_zones.is_a?(Regexp)
583
- priority_zones = zones.select { |z| z =~ priority_zones }
583
+ priority_zones = zones.select { |z| z.match?(priority_zones) }
584
584
  end
585
585
 
586
586
  zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
587
- zone_options.safe_concat content_tag("option".freeze, "-------------", value: "", disabled: true)
587
+ zone_options.safe_concat content_tag("option", "-------------", value: "", disabled: true)
588
588
  zone_options.safe_concat "\n"
589
589
 
590
590
  zones = zones - priority_zones
@@ -654,7 +654,7 @@ module ActionView
654
654
  #
655
655
  # ==== Gotcha
656
656
  #
657
- # The HTML specification says when nothing is select on a collection of radio buttons
657
+ # The HTML specification says when nothing is selected on a collection of radio buttons
658
658
  # web browsers do not send any value to server.
659
659
  # Unfortunately this introduces a gotcha:
660
660
  # if a +User+ model has a +category_id+ field and in the form no category is selected, no +category_id+ parameter is sent. So,
@@ -794,7 +794,7 @@ module ActionView
794
794
  def extract_values_from_collection(collection, value_method, selected)
795
795
  if selected.is_a?(Proc)
796
796
  collection.map do |element|
797
- element.send(value_method) if selected.call(element)
797
+ element.public_send(value_method) if selected.call(element)
798
798
  end.compact
799
799
  else
800
800
  selected
@@ -802,7 +802,7 @@ module ActionView
802
802
  end
803
803
 
804
804
  def value_for_collection(item, value)
805
- value.respond_to?(:call) ? value.call(item) : item.send(value)
805
+ value.respond_to?(:call) ? value.call(item) : item.public_send(value)
806
806
  end
807
807
 
808
808
  def prompt_text(prompt)