actionview 5.2.8.1 → 6.0.6.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.

Potentially problematic release.


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

Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +280 -94
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -3
  5. data/lib/action_view/base.rb +108 -11
  6. data/lib/action_view/buffers.rb +15 -0
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +5 -9
  9. data/lib/action_view/digestor.rb +12 -20
  10. data/lib/action_view/flows.rb +0 -1
  11. data/lib/action_view/gem_version.rb +3 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  13. data/lib/action_view/helpers/asset_tag_helper.rb +8 -31
  14. data/lib/action_view/helpers/asset_url_helper.rb +4 -3
  15. data/lib/action_view/helpers/cache_helper.rb +19 -12
  16. data/lib/action_view/helpers/capture_helper.rb +4 -0
  17. data/lib/action_view/helpers/csp_helper.rb +4 -2
  18. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  19. data/lib/action_view/helpers/date_helper.rb +70 -27
  20. data/lib/action_view/helpers/form_helper.rb +240 -8
  21. data/lib/action_view/helpers/form_options_helper.rb +27 -18
  22. data/lib/action_view/helpers/form_tag_helper.rb +17 -15
  23. data/lib/action_view/helpers/javascript_helper.rb +9 -8
  24. data/lib/action_view/helpers/number_helper.rb +8 -2
  25. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  26. data/lib/action_view/helpers/rendering_helper.rb +6 -4
  27. data/lib/action_view/helpers/sanitize_helper.rb +12 -18
  28. data/lib/action_view/helpers/tag_helper.rb +8 -7
  29. data/lib/action_view/helpers/tags/base.rb +9 -6
  30. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  31. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  32. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  33. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  34. data/lib/action_view/helpers/tags/color_field.rb +1 -2
  35. data/lib/action_view/helpers/tags/date_field.rb +0 -1
  36. data/lib/action_view/helpers/tags/date_select.rb +0 -1
  37. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  38. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -1
  39. data/lib/action_view/helpers/tags/label.rb +0 -1
  40. data/lib/action_view/helpers/tags/month_field.rb +0 -1
  41. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  42. data/lib/action_view/helpers/tags/select.rb +0 -1
  43. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  44. data/lib/action_view/helpers/tags/time_field.rb +0 -1
  45. data/lib/action_view/helpers/tags/translator.rb +1 -6
  46. data/lib/action_view/helpers/tags/week_field.rb +0 -1
  47. data/lib/action_view/helpers/text_helper.rb +3 -4
  48. data/lib/action_view/helpers/translation_helper.rb +19 -17
  49. data/lib/action_view/helpers/url_helper.rb +14 -14
  50. data/lib/action_view/helpers.rb +0 -2
  51. data/lib/action_view/layouts.rb +5 -8
  52. data/lib/action_view/log_subscriber.rb +6 -7
  53. data/lib/action_view/lookup_context.rb +75 -32
  54. data/lib/action_view/path_set.rb +5 -11
  55. data/lib/action_view/railtie.rb +24 -1
  56. data/lib/action_view/record_identifier.rb +2 -3
  57. data/lib/action_view/renderer/abstract_renderer.rb +56 -4
  58. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +63 -17
  59. data/lib/action_view/renderer/partial_renderer.rb +67 -57
  60. data/lib/action_view/renderer/renderer.rb +16 -4
  61. data/lib/action_view/renderer/streaming_template_renderer.rb +5 -7
  62. data/lib/action_view/renderer/template_renderer.rb +25 -20
  63. data/lib/action_view/rendering.rb +51 -32
  64. data/lib/action_view/routing_url_for.rb +12 -11
  65. data/lib/action_view/template/error.rb +30 -15
  66. data/lib/action_view/template/handlers/builder.rb +2 -2
  67. data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
  68. data/lib/action_view/template/handlers/erb.rb +17 -8
  69. data/lib/action_view/template/handlers/html.rb +1 -1
  70. data/lib/action_view/template/handlers/raw.rb +2 -2
  71. data/lib/action_view/template/handlers.rb +27 -1
  72. data/lib/action_view/template/html.rb +14 -5
  73. data/lib/action_view/template/inline.rb +22 -0
  74. data/lib/action_view/template/raw_file.rb +28 -0
  75. data/lib/action_view/template/resolver.rb +134 -135
  76. data/lib/action_view/template/sources/file.rb +17 -0
  77. data/lib/action_view/template/sources.rb +13 -0
  78. data/lib/action_view/template/text.rb +5 -3
  79. data/lib/action_view/template.rb +102 -71
  80. data/lib/action_view/test_case.rb +3 -4
  81. data/lib/action_view/testing/resolvers.rb +33 -21
  82. data/lib/action_view/unbound_template.rb +31 -0
  83. data/lib/action_view/view_paths.rb +25 -2
  84. data/lib/action_view.rb +4 -2
  85. data/lib/assets/compiled/rails-ujs.js +30 -4
  86. metadata +27 -18
  87. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -16,7 +16,7 @@ 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
  #
@@ -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,7 +69,7 @@ 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
  #
@@ -82,7 +82,7 @@ module ActionView
82
82
  #
83
83
  # 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
84
  #
85
- # collection_select(:post, :category_id, Category.all, :id, :name, {disabled: -> (category) { category.archived? }})
85
+ # collection_select(:post, :category_id, Category.all, :id, :name, { disabled: -> (category) { category.archived? } })
86
86
  #
87
87
  # If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
88
88
  # <select name="post[category_id]" id="post_category_id">
@@ -107,7 +107,7 @@ module ActionView
107
107
  #
108
108
  # For example:
109
109
  #
110
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { include_blank: true })
110
+ # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
111
111
  #
112
112
  # would become:
113
113
  #
@@ -323,12 +323,12 @@ module ActionView
323
323
  #
324
324
  # You can optionally provide HTML attributes as the last element of the array.
325
325
  #
326
- # options_for_select([ "Denmark", ["USA", {class: 'bold'}], "Sweden" ], ["USA", "Sweden"])
326
+ # options_for_select([ "Denmark", ["USA", { class: 'bold' }], "Sweden" ], ["USA", "Sweden"])
327
327
  # # => <option value="Denmark">Denmark</option>
328
328
  # # => <option value="USA" class="bold" selected="selected">USA</option>
329
329
  # # => <option value="Sweden" selected="selected">Sweden</option>
330
330
  #
331
- # options_for_select([["Dollar", "$", {class: "bold"}], ["Kroner", "DKK", {onclick: "alert('HI');"}]])
331
+ # options_for_select([["Dollar", "$", { class: "bold" }], ["Kroner", "DKK", { onclick: "alert('HI');" }]])
332
332
  # # => <option value="$" class="bold">Dollar</option>
333
333
  # # => <option value="DKK" onclick="alert('HI');">Kroner</option>
334
334
  #
@@ -463,7 +463,7 @@ module ActionView
463
463
  option_tags = options_from_collection_for_select(
464
464
  value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
465
465
 
466
- content_tag("optgroup".freeze, option_tags, label: value_for_collection(group, group_label_method))
466
+ content_tag("optgroup", option_tags, label: value_for_collection(group, group_label_method))
467
467
  end.join.html_safe
468
468
  end
469
469
 
@@ -535,7 +535,7 @@ module ActionView
535
535
  body = "".html_safe
536
536
 
537
537
  if prompt
538
- body.safe_concat content_tag("option".freeze, prompt_text(prompt), value: "")
538
+ body.safe_concat content_tag("option", prompt_text(prompt), value: "")
539
539
  end
540
540
 
541
541
  grouped_options.each do |container|
@@ -548,7 +548,7 @@ module ActionView
548
548
  end
549
549
 
550
550
  html_attributes = { label: label }.merge!(html_attributes)
551
- body.safe_concat content_tag("optgroup".freeze, options_for_select(container, selected_key), html_attributes)
551
+ body.safe_concat content_tag("optgroup", options_for_select(container, selected_key), html_attributes)
552
552
  end
553
553
 
554
554
  body
@@ -566,9 +566,10 @@ module ActionView
566
566
  # an ActiveSupport::TimeZone.
567
567
  #
568
568
  # 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.
569
+ # be obtained in Active Record as a value object). The +model+ parameter
570
+ # must respond to +all+ and return an array of objects that represent time
571
+ # zones; each object must respond to +name+. If a Regexp is given it will
572
+ # attempt to match the zones using the <code>=~<code> operator.
572
573
  #
573
574
  # NOTE: Only the option tags are returned, you have to wrap this call in
574
575
  # a regular HTML select tag.
@@ -584,7 +585,7 @@ module ActionView
584
585
  end
585
586
 
586
587
  zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
587
- zone_options.safe_concat content_tag("option".freeze, "-------------", value: "", disabled: true)
588
+ zone_options.safe_concat content_tag("option", "-------------", value: "", disabled: true)
588
589
  zone_options.safe_concat "\n"
589
590
 
590
591
  zones = zones - priority_zones
@@ -654,7 +655,7 @@ module ActionView
654
655
  #
655
656
  # ==== Gotcha
656
657
  #
657
- # The HTML specification says when nothing is select on a collection of radio buttons
658
+ # The HTML specification says when nothing is selected on a collection of radio buttons
658
659
  # web browsers do not send any value to server.
659
660
  # Unfortunately this introduces a gotcha:
660
661
  # 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 +795,7 @@ module ActionView
794
795
  def extract_values_from_collection(collection, value_method, selected)
795
796
  if selected.is_a?(Proc)
796
797
  collection.map do |element|
797
- element.send(value_method) if selected.call(element)
798
+ public_or_deprecated_send(element, value_method) if selected.call(element)
798
799
  end.compact
799
800
  else
800
801
  selected
@@ -802,7 +803,15 @@ module ActionView
802
803
  end
803
804
 
804
805
  def value_for_collection(item, value)
805
- value.respond_to?(:call) ? value.call(item) : item.send(value)
806
+ value.respond_to?(:call) ? value.call(item) : public_or_deprecated_send(item, value)
807
+ end
808
+
809
+ def public_or_deprecated_send(item, value)
810
+ item.public_send(value)
811
+ rescue NoMethodError
812
+ raise unless item.respond_to?(value, true) && !item.respond_to?(value)
813
+ ActiveSupport::Deprecation.warn "Using private methods from view helpers is deprecated (calling private #{item.class}##{value})"
814
+ item.send(value)
806
815
  end
807
816
 
808
817
  def prompt_text(prompt)
@@ -22,7 +22,9 @@ module ActionView
22
22
  mattr_accessor :embed_authenticity_token_in_remote_forms
23
23
  self.embed_authenticity_token_in_remote_forms = nil
24
24
 
25
- # Starts a form tag that points the action to a url configured with <tt>url_for_options</tt> just like
25
+ mattr_accessor :default_enforce_utf8, default: true
26
+
27
+ # Starts a form tag that points the action to a URL configured with <tt>url_for_options</tt> just like
26
28
  # ActionController::Base#url_for. The method for the form defaults to POST.
27
29
  #
28
30
  # ==== Options
@@ -135,7 +137,8 @@ module ActionView
135
137
  html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
136
138
 
137
139
  if options.include?(:include_blank)
138
- include_blank = options.delete(:include_blank)
140
+ include_blank = options[:include_blank]
141
+ options = options.except(:include_blank)
139
142
  options_for_blank_options_tag = { value: "" }
140
143
 
141
144
  if include_blank == true
@@ -144,15 +147,15 @@ module ActionView
144
147
  end
145
148
 
146
149
  if include_blank
147
- option_tags = content_tag("option".freeze, include_blank, options_for_blank_options_tag).safe_concat(option_tags)
150
+ option_tags = content_tag("option", include_blank, options_for_blank_options_tag).safe_concat(option_tags)
148
151
  end
149
152
  end
150
153
 
151
154
  if prompt = options.delete(:prompt)
152
- option_tags = content_tag("option".freeze, prompt, value: "").safe_concat(option_tags)
155
+ option_tags = content_tag("option", prompt, value: "").safe_concat(option_tags)
153
156
  end
154
157
 
155
- content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
158
+ content_tag "select", option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
156
159
  end
157
160
 
158
161
  # Creates a standard text field; use these text fields to input smaller chunks of text like a username
@@ -389,8 +392,8 @@ module ActionView
389
392
  # * Any other key creates standard HTML options for the tag.
390
393
  #
391
394
  # ==== Examples
392
- # radio_button_tag 'gender', 'male'
393
- # # => <input id="gender_male" name="gender" type="radio" value="male" />
395
+ # radio_button_tag 'favorite_color', 'maroon'
396
+ # # => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" />
394
397
  #
395
398
  # radio_button_tag 'receive_updates', 'no', true
396
399
  # # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
@@ -577,7 +580,7 @@ module ActionView
577
580
  # # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
578
581
  def field_set_tag(legend = nil, options = nil, &block)
579
582
  output = tag(:fieldset, options, true)
580
- output.safe_concat(content_tag("legend".freeze, legend)) unless legend.blank?
583
+ output.safe_concat(content_tag("legend", legend)) unless legend.blank?
581
584
  output.concat(capture(&block)) if block_given?
582
585
  output.safe_concat("</fieldset>")
583
586
  end
@@ -869,7 +872,7 @@ module ActionView
869
872
  })
870
873
  end
871
874
 
872
- if html_options.delete("enforce_utf8") { true }
875
+ if html_options.delete("enforce_utf8") { default_enforce_utf8 }
873
876
  utf8_enforcer_tag + method_tag
874
877
  else
875
878
  method_tag
@@ -893,16 +896,15 @@ module ActionView
893
896
  end
894
897
 
895
898
  def set_default_disable_with(value, tag_options)
896
- return unless ActionView::Base.automatically_disable_submit_tag
897
- data = tag_options["data"]
899
+ data = tag_options.fetch("data", {})
898
900
 
899
- unless tag_options["data-disable-with"] == false || (data && data["disable_with"] == false)
901
+ if tag_options["data-disable-with"] == false || data["disable_with"] == false
902
+ data.delete("disable_with")
903
+ elsif ActionView::Base.automatically_disable_submit_tag
900
904
  disable_with_text = tag_options["data-disable-with"]
901
- disable_with_text ||= data["disable_with"] if data
905
+ disable_with_text ||= data["disable_with"]
902
906
  disable_with_text ||= value.to_s.clone
903
907
  tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
904
- else
905
- data.delete("disable_with") if data
906
908
  end
907
909
 
908
910
  tag_options.delete("data-disable-with")
@@ -17,8 +17,8 @@ module ActionView
17
17
  "$" => "\\$"
18
18
  }
19
19
 
20
- JS_ESCAPE_MAP["\342\200\250".dup.force_encoding(Encoding::UTF_8).encode!] = "&#x2028;"
21
- JS_ESCAPE_MAP["\342\200\251".dup.force_encoding(Encoding::UTF_8).encode!] = "&#x2029;"
20
+ JS_ESCAPE_MAP[(+"\342\200\250").force_encoding(Encoding::UTF_8).encode!] = "&#x2028;"
21
+ JS_ESCAPE_MAP[(+"\342\200\251").force_encoding(Encoding::UTF_8).encode!] = "&#x2029;"
22
22
 
23
23
  # Escapes carriage returns and single and double quotes for JavaScript segments.
24
24
  #
@@ -27,12 +27,13 @@ module ActionView
27
27
  #
28
28
  # $('some_element').replaceWith('<%= j render 'some/element_template' %>');
29
29
  def escape_javascript(javascript)
30
- if javascript
31
- result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u) { |match| JS_ESCAPE_MAP[match] }
32
- javascript.html_safe? ? result.html_safe : result
30
+ javascript = javascript.to_s
31
+ if javascript.empty?
32
+ result = ""
33
33
  else
34
- ""
34
+ result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP)
35
35
  end
36
+ javascript.html_safe? ? result.html_safe : result
36
37
  end
37
38
 
38
39
  alias_method :j, :escape_javascript
@@ -67,7 +68,7 @@ module ActionView
67
68
  # <% end -%>
68
69
  #
69
70
  # If you have a content security policy enabled then you can add an automatic
70
- # nonce value by passing +nonce: true+ as part of +html_options+. Example:
71
+ # nonce value by passing <tt>nonce: true</tt> as part of +html_options+. Example:
71
72
  #
72
73
  # <%= javascript_tag nonce: true do -%>
73
74
  # alert('All is good')
@@ -85,7 +86,7 @@ module ActionView
85
86
  html_options[:nonce] = content_security_policy_nonce
86
87
  end
87
88
 
88
- content_tag("script".freeze, javascript_cdata_section(content), html_options)
89
+ content_tag("script", javascript_cdata_section(content), html_options)
89
90
  end
90
91
 
91
92
  def javascript_cdata_section(content) #:nodoc:
@@ -57,7 +57,7 @@ module ActionView
57
57
  #
58
58
  # number_to_phone(75561234567, pattern: /(\d{1,4})(\d{4})(\d{4})$/, area_code: true)
59
59
  # # => "(755) 6123-4567"
60
- # number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/))
60
+ # number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)
61
61
  # # => "133-1234-5678"
62
62
  def number_to_phone(number, options = {})
63
63
  return unless number
@@ -100,6 +100,9 @@ module ActionView
100
100
  # absolute value of the number.
101
101
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
102
102
  # the argument is invalid.
103
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
104
+ # insignificant zeros after the decimal separator (defaults to
105
+ # +false+).
103
106
  #
104
107
  # ==== Examples
105
108
  #
@@ -111,12 +114,16 @@ module ActionView
111
114
  #
112
115
  # number_to_currency("123a456", raise: true) # => InvalidNumberError
113
116
  #
117
+ # number_to_currency(-0.456789, precision: 0)
118
+ # # => "$0"
114
119
  # number_to_currency(-1234567890.50, negative_format: "(%u%n)")
115
120
  # # => ($1,234,567,890.50)
116
121
  # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "")
117
122
  # # => R$1234567890,50
118
123
  # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u")
119
124
  # # => 1234567890,50 R$
125
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
126
+ # # => "$1,234,567,890.5"
120
127
  def number_to_currency(number, options = {})
121
128
  delegate_number_helper_method(:number_to_currency, number, options)
122
129
  end
@@ -398,7 +405,6 @@ module ActionView
398
405
  end
399
406
 
400
407
  private
401
-
402
408
  def delegate_number_helper_method(method, number, options)
403
409
  return unless number
404
410
  options = escape_unsafe_options(options.symbolize_keys)
@@ -38,7 +38,7 @@ module ActionView #:nodoc:
38
38
 
39
39
  # Converts the array to a comma-separated sentence where the last element is
40
40
  # joined by the connector word. This is the html_safe-aware version of
41
- # ActiveSupport's {Array#to_sentence}[http://api.rubyonrails.org/classes/Array.html#method-i-to_sentence].
41
+ # ActiveSupport's {Array#to_sentence}[https://api.rubyonrails.org/classes/Array.html#method-i-to_sentence].
42
42
  #
43
43
  def to_sentence(array, options = {})
44
44
  options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
@@ -27,10 +27,12 @@ module ActionView
27
27
  def render(options = {}, locals = {}, &block)
28
28
  case options
29
29
  when Hash
30
- if block_given?
31
- view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
32
- else
33
- view_renderer.render(self, options)
30
+ in_rendering_context(options) do |renderer|
31
+ if block_given?
32
+ view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
33
+ else
34
+ view_renderer.render(self, options)
35
+ end
34
36
  end
35
37
  else
36
38
  view_renderer.render_partial(self, partial: options, locals: locals, &block)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/try"
4
3
  require "rails-html-sanitizer"
5
4
 
6
5
  module ActionView
@@ -10,14 +9,14 @@ module ActionView
10
9
  # These helper methods extend Action View making them callable within your template files.
11
10
  module SanitizeHelper
12
11
  extend ActiveSupport::Concern
13
- # Sanitizes HTML input, stripping all tags and attributes that aren't whitelisted.
12
+ # Sanitizes HTML input, stripping all but known-safe tags and attributes.
14
13
  #
15
14
  # It also strips href/src attributes with unsafe protocols like
16
15
  # <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
17
16
  # ASCII, and hex character references to work around these protocol filters.
18
17
  # All special characters will be escaped.
19
18
  #
20
- # The default sanitizer is Rails::Html::WhiteListSanitizer. See {Rails HTML
19
+ # The default sanitizer is Rails::Html::SafeListSanitizer. See {Rails HTML
21
20
  # Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
22
21
  #
23
22
  # Custom sanitization rules can also be provided.
@@ -40,7 +39,7 @@ module ActionView
40
39
  #
41
40
  # <%= sanitize @comment.body %>
42
41
  #
43
- # Providing custom whitelisted tags and attributes:
42
+ # Providing custom lists of permitted tags and attributes:
44
43
  #
45
44
  # <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
46
45
  #
@@ -80,12 +79,12 @@ module ActionView
80
79
  # config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
81
80
  # config.action_view.sanitized_allowed_attributes = ['href', 'title']
82
81
  def sanitize(html, options = {})
83
- self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
82
+ self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
84
83
  end
85
84
 
86
85
  # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
87
86
  def sanitize_css(style)
88
- self.class.white_list_sanitizer.sanitize_css(style)
87
+ self.class.safe_list_sanitizer.sanitize_css(style)
89
88
  end
90
89
 
91
90
  # Strips all HTML tags from +html+, including comments and special characters.
@@ -123,20 +122,18 @@ module ActionView
123
122
  end
124
123
 
125
124
  module ClassMethods #:nodoc:
126
- attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
125
+ attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer
127
126
 
128
- # Vendors the full, link and white list sanitizers.
129
- # Provided strictly for compatibility and can be removed in Rails 5.1.
130
127
  def sanitizer_vendor
131
128
  Rails::Html::Sanitizer
132
129
  end
133
130
 
134
131
  def sanitized_allowed_tags
135
- sanitizer_vendor.white_list_sanitizer.allowed_tags
132
+ sanitizer_vendor.safe_list_sanitizer.allowed_tags
136
133
  end
137
134
 
138
135
  def sanitized_allowed_attributes
139
- sanitizer_vendor.white_list_sanitizer.allowed_attributes
136
+ sanitizer_vendor.safe_list_sanitizer.allowed_attributes
140
137
  end
141
138
 
142
139
  # Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
@@ -145,7 +142,6 @@ module ActionView
145
142
  # class Application < Rails::Application
146
143
  # config.action_view.full_sanitizer = MySpecialSanitizer.new
147
144
  # end
148
- #
149
145
  def full_sanitizer
150
146
  @full_sanitizer ||= sanitizer_vendor.full_sanitizer.new
151
147
  end
@@ -156,20 +152,18 @@ module ActionView
156
152
  # class Application < Rails::Application
157
153
  # config.action_view.link_sanitizer = MySpecialSanitizer.new
158
154
  # end
159
- #
160
155
  def link_sanitizer
161
156
  @link_sanitizer ||= sanitizer_vendor.link_sanitizer.new
162
157
  end
163
158
 
164
- # Gets the Rails::Html::WhiteListSanitizer instance used by sanitize and +sanitize_css+.
159
+ # Gets the Rails::Html::SafeListSanitizer instance used by sanitize and +sanitize_css+.
165
160
  # Replace with any object that responds to +sanitize+.
166
161
  #
167
162
  # class Application < Rails::Application
168
- # config.action_view.white_list_sanitizer = MySpecialSanitizer.new
163
+ # config.action_view.safe_list_sanitizer = MySpecialSanitizer.new
169
164
  # end
170
- #
171
- def white_list_sanitizer
172
- @white_list_sanitizer ||= sanitizer_vendor.white_list_sanitizer.new
165
+ def safe_list_sanitizer
166
+ @safe_list_sanitizer ||= sanitizer_vendor.safe_list_sanitizer.new
173
167
  end
174
168
  end
175
169
  end
@@ -65,7 +65,7 @@ module ActionView
65
65
 
66
66
  def tag_options(options, escape = true)
67
67
  return if options.blank?
68
- output = "".dup
68
+ output = +""
69
69
  sep = " "
70
70
  options.each_pair do |key, value|
71
71
  if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
@@ -95,11 +95,12 @@ module ActionView
95
95
  key = ERB::Util.xml_name_escape(key) if escape
96
96
 
97
97
  if value.is_a?(Array)
98
- value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze)
98
+ value = escape ? safe_join(value, " ") : value.join(" ")
99
99
  else
100
- value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
100
+ value = escape ? ERB::Util.unwrapped_html_escape(value).dup : value.to_s.dup
101
101
  end
102
- %(#{key}="#{value.gsub('"'.freeze, '&quot;'.freeze)}")
102
+ value.gsub!('"', "&quot;")
103
+ %(#{key}="#{value}")
103
104
  end
104
105
 
105
106
  private
@@ -122,7 +123,7 @@ module ActionView
122
123
  escape_attributes_option_provided = options.has_key?(:escape_attributes)
123
124
 
124
125
  if escape_attributes_option_provided
125
- ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
126
+ ActiveSupport::Deprecation.warn(<<~MSG)
126
127
  Use of the option :escape_attributes is deprecated. It currently \
127
128
  escapes both names and values of tags and attributes and it is \
128
129
  equivalent to :escape. If any of them are enabled, the escaping \
@@ -257,10 +258,10 @@ module ActionView
257
258
  # tag("img", src: "open & shut.png")
258
259
  # # => <img src="open &amp; shut.png" />
259
260
  #
260
- # tag("img", {src: "open &amp; shut.png"}, false, false)
261
+ # tag("img", { src: "open &amp; shut.png" }, false, false)
261
262
  # # => <img src="open &amp; shut.png" />
262
263
  #
263
- # tag("div", data: {name: 'Stephen', city_state: %w(Chicago IL)})
264
+ # tag("div", data: { name: 'Stephen', city_state: %w(Chicago IL) })
264
265
  # # => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />
265
266
  def tag(name = nil, options = nil, open = false, escape = true)
266
267
  if name.nil?
@@ -34,7 +34,6 @@ module ActionView
34
34
  end
35
35
 
36
36
  private
37
-
38
37
  def value
39
38
  if @allow_method_names_outside_object
40
39
  object.public_send @method_name if object && object.respond_to?(@method_name)
@@ -109,11 +108,11 @@ module ActionView
109
108
  # a little duplication to construct less strings
110
109
  case
111
110
  when @object_name.empty?
112
- "#{sanitized_method_name}#{"[]" if multiple}"
111
+ "#{sanitized_method_name}#{multiple ? "[]" : ""}"
113
112
  when index
114
- "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
113
+ "#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
115
114
  else
116
- "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
115
+ "#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
117
116
  end
118
117
  end
119
118
 
@@ -138,7 +137,7 @@ module ActionView
138
137
  end
139
138
 
140
139
  def sanitized_value(value)
141
- value.to_s.gsub(/\s/, "_").gsub(/[^-[[:word:]]]/, "").mb_chars.downcase.to_s
140
+ value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
142
141
  end
143
142
 
144
143
  def select_content_tag(option_tags, options, html_options)
@@ -170,7 +169,11 @@ module ActionView
170
169
  option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags
171
170
  end
172
171
  if value.blank? && options[:prompt]
173
- option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), value: "") + "\n" + option_tags
172
+ tag_options = { value: "" }.tap do |prompt_opts|
173
+ prompt_opts[:disabled] = true if options[:disabled] == ""
174
+ prompt_opts[:selected] = true if options[:selected] == ""
175
+ end
176
+ option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
174
177
  end
175
178
  option_tags
176
179
  end
@@ -39,7 +39,6 @@ module ActionView
39
39
  end
40
40
 
41
41
  private
42
-
43
42
  def checked?(value)
44
43
  case value
45
44
  when TrueClass, FalseClass
@@ -22,7 +22,6 @@ module ActionView
22
22
  end
23
23
 
24
24
  private
25
-
26
25
  def render_component(builder)
27
26
  builder.check_box + builder.label
28
27
  end
@@ -37,7 +37,6 @@ module ActionView
37
37
  end
38
38
 
39
39
  private
40
-
41
40
  def instantiate_builder(builder_class, item, value, text, html_options)
42
41
  builder_class.new(@template_object, @object_name, @method_name, item,
43
42
  sanitize_attribute_name(value), text, value, html_options)
@@ -21,7 +21,6 @@ module ActionView
21
21
  end
22
22
 
23
23
  private
24
-
25
24
  def render_component(builder)
26
25
  builder.radio_button + builder.label
27
26
  end
@@ -12,10 +12,9 @@ module ActionView
12
12
  end
13
13
 
14
14
  private
15
-
16
15
  def validate_color_string(string)
17
16
  regex = /#[0-9a-fA-F]{6}/
18
- if regex.match(string)
17
+ if regex.match?(string)
19
18
  string.downcase
20
19
  else
21
20
  "#000000"
@@ -5,7 +5,6 @@ module ActionView
5
5
  module Tags # :nodoc:
6
6
  class DateField < DatetimeField # :nodoc:
7
7
  private
8
-
9
8
  def format_date(value)
10
9
  value.try(:strftime, "%Y-%m-%d")
11
10
  end
@@ -23,7 +23,6 @@ module ActionView
23
23
  end
24
24
 
25
25
  private
26
-
27
26
  def select_type
28
27
  self.class.select_type
29
28
  end
@@ -14,7 +14,6 @@ module ActionView
14
14
  end
15
15
 
16
16
  private
17
-
18
17
  def format_date(value)
19
18
  raise NotImplementedError
20
19
  end
@@ -11,7 +11,6 @@ module ActionView
11
11
  end
12
12
 
13
13
  private
14
-
15
14
  def format_date(value)
16
15
  value.try(:strftime, "%Y-%m-%dT%T")
17
16
  end
@@ -71,7 +71,6 @@ module ActionView
71
71
  end
72
72
 
73
73
  private
74
-
75
74
  def render_component(builder)
76
75
  builder.translation
77
76
  end