actionview 5.2.8.1 → 6.0.0.beta1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +106 -162
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/action_view/buffers.rb +15 -0
  6. data/lib/action_view/context.rb +5 -4
  7. data/lib/action_view/digestor.rb +7 -6
  8. data/lib/action_view/gem_version.rb +4 -4
  9. data/lib/action_view/helpers/asset_tag_helper.rb +4 -27
  10. data/lib/action_view/helpers/asset_url_helper.rb +4 -3
  11. data/lib/action_view/helpers/cache_helper.rb +18 -10
  12. data/lib/action_view/helpers/capture_helper.rb +4 -0
  13. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  14. data/lib/action_view/helpers/date_helper.rb +69 -25
  15. data/lib/action_view/helpers/form_helper.rb +240 -8
  16. data/lib/action_view/helpers/form_options_helper.rb +23 -15
  17. data/lib/action_view/helpers/form_tag_helper.rb +9 -9
  18. data/lib/action_view/helpers/javascript_helper.rb +10 -11
  19. data/lib/action_view/helpers/number_helper.rb +5 -0
  20. data/lib/action_view/helpers/sanitize_helper.rb +3 -3
  21. data/lib/action_view/helpers/tag_helper.rb +13 -43
  22. data/lib/action_view/helpers/tags/base.rb +8 -4
  23. data/lib/action_view/helpers/tags/color_field.rb +1 -1
  24. data/lib/action_view/helpers/tags/translator.rb +1 -6
  25. data/lib/action_view/helpers/text_helper.rb +3 -3
  26. data/lib/action_view/helpers/translation_helper.rb +11 -18
  27. data/lib/action_view/helpers/url_helper.rb +14 -14
  28. data/lib/action_view/helpers.rb +0 -2
  29. data/lib/action_view/log_subscriber.rb +6 -6
  30. data/lib/action_view/lookup_context.rb +4 -4
  31. data/lib/action_view/railtie.rb +18 -0
  32. data/lib/action_view/record_identifier.rb +2 -2
  33. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +40 -1
  34. data/lib/action_view/renderer/partial_renderer.rb +2 -2
  35. data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
  36. data/lib/action_view/rendering.rb +5 -4
  37. data/lib/action_view/routing_url_for.rb +12 -11
  38. data/lib/action_view/template/handlers/erb.rb +12 -2
  39. data/lib/action_view/template/resolver.rb +56 -16
  40. data/lib/action_view/template.rb +25 -8
  41. data/lib/action_view/test_case.rb +1 -1
  42. data/lib/action_view/testing/resolvers.rb +1 -1
  43. data/lib/action_view.rb +1 -1
  44. data/lib/assets/compiled/rails-ujs.js +39 -22
  45. metadata +17 -18
  46. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -22,6 +22,8 @@ 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
+ mattr_accessor :default_enforce_utf8, default: true
26
+
25
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
  #
@@ -144,15 +146,15 @@ module ActionView
144
146
  end
145
147
 
146
148
  if include_blank
147
- option_tags = content_tag("option".freeze, include_blank, options_for_blank_options_tag).safe_concat(option_tags)
149
+ option_tags = content_tag("option", include_blank, options_for_blank_options_tag).safe_concat(option_tags)
148
150
  end
149
151
  end
150
152
 
151
153
  if prompt = options.delete(:prompt)
152
- option_tags = content_tag("option".freeze, prompt, value: "").safe_concat(option_tags)
154
+ option_tags = content_tag("option", prompt, value: "").safe_concat(option_tags)
153
155
  end
154
156
 
155
- content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
157
+ content_tag "select", option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
156
158
  end
157
159
 
158
160
  # Creates a standard text field; use these text fields to input smaller chunks of text like a username
@@ -163,8 +165,6 @@ module ActionView
163
165
  # * <tt>:size</tt> - The number of visible characters that will fit in the input.
164
166
  # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
165
167
  # * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
166
- # If set to true, use a translation is found in the current I18n locale
167
- # (through helpers.placeholders.<modelname>.<attribute>).
168
168
  # * Any other key creates standard HTML attributes for the tag.
169
169
  #
170
170
  # ==== Examples
@@ -389,8 +389,8 @@ module ActionView
389
389
  # * Any other key creates standard HTML options for the tag.
390
390
  #
391
391
  # ==== Examples
392
- # radio_button_tag 'gender', 'male'
393
- # # => <input id="gender_male" name="gender" type="radio" value="male" />
392
+ # radio_button_tag 'favorite_color', 'maroon'
393
+ # # => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" />
394
394
  #
395
395
  # radio_button_tag 'receive_updates', 'no', true
396
396
  # # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
@@ -577,7 +577,7 @@ module ActionView
577
577
  # # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
578
578
  def field_set_tag(legend = nil, options = nil, &block)
579
579
  output = tag(:fieldset, options, true)
580
- output.safe_concat(content_tag("legend".freeze, legend)) unless legend.blank?
580
+ output.safe_concat(content_tag("legend", legend)) unless legend.blank?
581
581
  output.concat(capture(&block)) if block_given?
582
582
  output.safe_concat("</fieldset>")
583
583
  end
@@ -869,7 +869,7 @@ module ActionView
869
869
  })
870
870
  end
871
871
 
872
- if html_options.delete("enforce_utf8") { true }
872
+ if html_options.delete("enforce_utf8") { default_enforce_utf8 }
873
873
  utf8_enforcer_tag + method_tag
874
874
  else
875
875
  method_tag
@@ -12,13 +12,11 @@ module ActionView
12
12
  "\n" => '\n',
13
13
  "\r" => '\n',
14
14
  '"' => '\\"',
15
- "'" => "\\'",
16
- "`" => "\\`",
17
- "$" => "\\$"
15
+ "'" => "\\'"
18
16
  }
19
17
 
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;"
18
+ JS_ESCAPE_MAP[(+"\342\200\250").force_encoding(Encoding::UTF_8).encode!] = "&#x2028;"
19
+ JS_ESCAPE_MAP[(+"\342\200\251").force_encoding(Encoding::UTF_8).encode!] = "&#x2029;"
22
20
 
23
21
  # Escapes carriage returns and single and double quotes for JavaScript segments.
24
22
  #
@@ -27,12 +25,13 @@ module ActionView
27
25
  #
28
26
  # $('some_element').replaceWith('<%= j render 'some/element_template' %>');
29
27
  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
28
+ javascript = javascript.to_s
29
+ if javascript.empty?
30
+ result = ""
33
31
  else
34
- ""
32
+ result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) { |match| JS_ESCAPE_MAP[match] }
35
33
  end
34
+ javascript.html_safe? ? result.html_safe : result
36
35
  end
37
36
 
38
37
  alias_method :j, :escape_javascript
@@ -67,7 +66,7 @@ module ActionView
67
66
  # <% end -%>
68
67
  #
69
68
  # 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:
69
+ # nonce value by passing <tt>nonce: true</tt> as part of +html_options+. Example:
71
70
  #
72
71
  # <%= javascript_tag nonce: true do -%>
73
72
  # alert('All is good')
@@ -85,7 +84,7 @@ module ActionView
85
84
  html_options[:nonce] = content_security_policy_nonce
86
85
  end
87
86
 
88
- content_tag("script".freeze, javascript_cdata_section(content), html_options)
87
+ content_tag("script", javascript_cdata_section(content), html_options)
89
88
  end
90
89
 
91
90
  def javascript_cdata_section(content) #:nodoc:
@@ -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
  #
@@ -117,6 +120,8 @@ module ActionView
117
120
  # # => R$1234567890,50
118
121
  # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u")
119
122
  # # => 1234567890,50 R$
123
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
124
+ # # => "$1,234,567,890.5"
120
125
  def number_to_currency(number, options = {})
121
126
  delegate_number_helper_method(:number_to_currency, number, options)
122
127
  end
@@ -10,7 +10,7 @@ module ActionView
10
10
  # These helper methods extend Action View making them callable within your template files.
11
11
  module SanitizeHelper
12
12
  extend ActiveSupport::Concern
13
- # Sanitizes HTML input, stripping all tags and attributes that aren't whitelisted.
13
+ # Sanitizes HTML input, stripping all but known-safe tags and attributes.
14
14
  #
15
15
  # It also strips href/src attributes with unsafe protocols like
16
16
  # <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
@@ -40,7 +40,7 @@ module ActionView
40
40
  #
41
41
  # <%= sanitize @comment.body %>
42
42
  #
43
- # Providing custom whitelisted tags and attributes:
43
+ # Providing custom lists of permitted tags and attributes:
44
44
  #
45
45
  # <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
46
46
  #
@@ -126,7 +126,7 @@ module ActionView
126
126
  attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
127
127
 
128
128
  # Vendors the full, link and white list sanitizers.
129
- # Provided strictly for compatibility and can be removed in Rails 5.1.
129
+ # Provided strictly for compatibility and can be removed in Rails 6.
130
130
  def sanitizer_vendor
131
131
  Rails::Html::Sanitizer
132
132
  end
@@ -41,31 +41,24 @@ module ActionView
41
41
  @view_context = view_context
42
42
  end
43
43
 
44
- def tag_string(name, content = nil, **options, &block)
45
- escape = handle_deprecated_escape_options(options)
44
+ def tag_string(name, content = nil, escape_attributes: true, **options, &block)
46
45
  content = @view_context.capture(self, &block) if block_given?
47
-
48
46
  if VOID_ELEMENTS.include?(name) && content.nil?
49
- "<#{name.to_s.dasherize}#{tag_options(options, escape)}>".html_safe
47
+ "<#{name.to_s.dasherize}#{tag_options(options, escape_attributes)}>".html_safe
50
48
  else
51
- content_tag_string(name.to_s.dasherize, content || "", options, escape)
49
+ content_tag_string(name.to_s.dasherize, content || "", options, escape_attributes)
52
50
  end
53
51
  end
54
52
 
55
53
  def content_tag_string(name, content, options, escape = true)
56
54
  tag_options = tag_options(options, escape) if options
57
-
58
- if escape
59
- name = ERB::Util.xml_name_escape(name)
60
- content = ERB::Util.unwrapped_html_escape(content)
61
- end
62
-
55
+ content = ERB::Util.unwrapped_html_escape(content) if escape
63
56
  "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
64
57
  end
65
58
 
66
59
  def tag_options(options, escape = true)
67
60
  return if options.blank?
68
- output = "".dup
61
+ output = +""
69
62
  sep = " "
70
63
  options.each_pair do |key, value|
71
64
  if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
@@ -92,14 +85,13 @@ module ActionView
92
85
  end
93
86
 
94
87
  def tag_option(key, value, escape)
95
- key = ERB::Util.xml_name_escape(key) if escape
96
-
97
88
  if value.is_a?(Array)
98
- value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze)
89
+ value = escape ? safe_join(value, " ") : value.join(" ")
99
90
  else
100
- value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
91
+ value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s.dup
101
92
  end
102
- %(#{key}="#{value.gsub('"'.freeze, '&quot;'.freeze)}")
93
+ value.gsub!('"', "&quot;")
94
+ %(#{key}="#{value}")
103
95
  end
104
96
 
105
97
  private
@@ -115,29 +107,8 @@ module ActionView
115
107
  true
116
108
  end
117
109
 
118
- def handle_deprecated_escape_options(options)
119
- # The option :escape_attributes has been merged into the options hash to be
120
- # able to warn when it is used, so we need to handle default values here.
121
- escape_option_provided = options.has_key?(:escape)
122
- escape_attributes_option_provided = options.has_key?(:escape_attributes)
123
-
124
- if escape_attributes_option_provided
125
- ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
126
- Use of the option :escape_attributes is deprecated. It currently \
127
- escapes both names and values of tags and attributes and it is \
128
- equivalent to :escape. If any of them are enabled, the escaping \
129
- is fully enabled.
130
- MSG
131
- end
132
-
133
- return true unless escape_option_provided || escape_attributes_option_provided
134
- escape_option = options.delete(:escape)
135
- escape_attributes_option = options.delete(:escape_attributes)
136
- escape_option || escape_attributes_option
137
- end
138
-
139
- def method_missing(called, *args, **options, &block)
140
- tag_string(called, *args, **options, &block)
110
+ def method_missing(called, *args, &block)
111
+ tag_string(called, *args, &block)
141
112
  end
142
113
  end
143
114
 
@@ -257,16 +228,15 @@ module ActionView
257
228
  # tag("img", src: "open & shut.png")
258
229
  # # => <img src="open &amp; shut.png" />
259
230
  #
260
- # tag("img", {src: "open &amp; shut.png"}, false, false)
231
+ # tag("img", { src: "open &amp; shut.png" }, false, false)
261
232
  # # => <img src="open &amp; shut.png" />
262
233
  #
263
- # tag("div", data: {name: 'Stephen', city_state: %w(Chicago IL)})
234
+ # tag("div", data: { name: 'Stephen', city_state: %w(Chicago IL) })
264
235
  # # => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />
265
236
  def tag(name = nil, options = nil, open = false, escape = true)
266
237
  if name.nil?
267
238
  tag_builder
268
239
  else
269
- name = ERB::Util.xml_name_escape(name) if escape
270
240
  "<#{name}#{tag_builder.tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
271
241
  end
272
242
  end
@@ -109,11 +109,11 @@ module ActionView
109
109
  # a little duplication to construct less strings
110
110
  case
111
111
  when @object_name.empty?
112
- "#{sanitized_method_name}#{"[]" if multiple}"
112
+ "#{sanitized_method_name}#{multiple ? "[]" : ""}"
113
113
  when index
114
- "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
114
+ "#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
115
115
  else
116
- "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
116
+ "#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
117
117
  end
118
118
  end
119
119
 
@@ -170,7 +170,11 @@ module ActionView
170
170
  option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags
171
171
  end
172
172
  if value.blank? && options[:prompt]
173
- option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), value: "") + "\n" + option_tags
173
+ tag_options = { value: "" }.tap do |prompt_opts|
174
+ prompt_opts[:disabled] = true if options[:disabled] == ""
175
+ prompt_opts[:selected] = true if options[:selected] == ""
176
+ end
177
+ option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
174
178
  end
175
179
  option_tags
176
180
  end
@@ -15,7 +15,7 @@ module ActionView
15
15
 
16
16
  def validate_color_string(string)
17
17
  regex = /#[0-9a-fA-F]{6}/
18
- if regex.match(string)
18
+ if regex.match?(string)
19
19
  string.downcase
20
20
  else
21
21
  "#000000"
@@ -16,13 +16,8 @@ module ActionView
16
16
  translated_attribute || human_attribute_name
17
17
  end
18
18
 
19
- # TODO Change this to private once we've dropped Ruby 2.2 support.
20
- # Workaround for Ruby 2.2 "private attribute?" warning.
21
- protected
22
-
23
- attr_reader :object_name, :method_and_value, :scope, :model
24
-
25
19
  private
20
+ attr_reader :object_name, :method_and_value, :scope, :model
26
21
 
27
22
  def i18n_default
28
23
  if model
@@ -188,7 +188,7 @@ module ActionView
188
188
 
189
189
  unless separator.empty?
190
190
  text.split(separator).each do |value|
191
- if value.match(regex)
191
+ if value.match?(regex)
192
192
  phrase = value
193
193
  break
194
194
  end
@@ -228,7 +228,7 @@ module ActionView
228
228
  # pluralize(2, 'Person', locale: :de)
229
229
  # # => 2 Personen
230
230
  def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
231
- word = if (count == 1 || count.to_s =~ /^1(\.0+)?$/)
231
+ word = if count == 1 || count.to_s =~ /^1(\.0+)?$/
232
232
  singular
233
233
  else
234
234
  plural || singular.pluralize(locale)
@@ -259,7 +259,7 @@ module ActionView
259
259
  # # => Once\r\nupon\r\na\r\ntime
260
260
  def word_wrap(text, line_width: 80, break_sequence: "\n")
261
261
  text.split("\n").collect! do |line|
262
- line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
262
+ line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").rstrip : line
263
263
  end * break_sequence
264
264
  end
265
265
 
@@ -59,11 +59,9 @@ module ActionView
59
59
  # they can provide HTML values for.
60
60
  def translate(key, options = {})
61
61
  options = options.dup
62
- has_default = options.has_key?(:default)
63
- remaining_defaults = Array(options.delete(:default)).compact
64
-
65
- if has_default && !remaining_defaults.first.kind_of?(Symbol)
66
- options[:default] = remaining_defaults
62
+ if options.has_key?(:default)
63
+ remaining_defaults = Array(options.delete(:default)).compact
64
+ options[:default] = remaining_defaults unless remaining_defaults.first.kind_of?(Symbol)
67
65
  end
68
66
 
69
67
  # If the user has explicitly decided to NOT raise errors, pass that option to I18n.
@@ -79,19 +77,14 @@ module ActionView
79
77
 
80
78
  if html_safe_translation_key?(key)
81
79
  html_safe_options = options.dup
82
-
83
80
  options.except(*I18n::RESERVED_KEYS).each do |name, value|
84
81
  unless name == :count && value.is_a?(Numeric)
85
82
  html_safe_options[name] = ERB::Util.html_escape(value.to_s)
86
83
  end
87
84
  end
88
-
89
- html_safe_options[:default] = MISSING_TRANSLATION unless html_safe_options[:default].blank?
90
-
91
85
  translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
92
-
93
- if translation.equal?(MISSING_TRANSLATION)
94
- options[:default].first
86
+ if translation.respond_to?(:map)
87
+ translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
95
88
  else
96
89
  translation.respond_to?(:html_safe) ? translation.html_safe : translation
97
90
  end
@@ -105,7 +98,7 @@ module ActionView
105
98
  raise e if raise_error
106
99
 
107
100
  keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
108
- title = "translation missing: #{keys.join('.')}".dup
101
+ title = +"translation missing: #{keys.join('.')}"
109
102
 
110
103
  interpolations = options.except(:default, :scope)
111
104
  if interpolations.any?
@@ -129,13 +122,13 @@ module ActionView
129
122
  alias :l :localize
130
123
 
131
124
  private
132
- MISSING_TRANSLATION = Object.new
133
- private_constant :MISSING_TRANSLATION
134
-
135
125
  def scope_key_by_partial(key)
136
- if key.to_s.first == "."
126
+ stringified_key = key.to_s
127
+ if stringified_key.first == "."
137
128
  if @virtual_path
138
- @virtual_path.gsub(%r{/_?}, ".") + key.to_s
129
+ @_scope_key_by_partial_cache ||= {}
130
+ @_scope_key_by_partial_cache[@virtual_path] ||= @virtual_path.gsub(%r{/_?}, ".")
131
+ "#{@_scope_key_by_partial_cache[@virtual_path]}#{stringified_key}"
139
132
  else
140
133
  raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
141
134
  end
@@ -200,9 +200,9 @@ module ActionView
200
200
  html_options = convert_options_to_data_attributes(options, html_options)
201
201
 
202
202
  url = url_for(options)
203
- html_options["href".freeze] ||= url
203
+ html_options["href"] ||= url
204
204
 
205
- content_tag("a".freeze, name || url, html_options, &block)
205
+ content_tag("a", name || url, html_options, &block)
206
206
  end
207
207
 
208
208
  # Generates a form containing a single button that submits to the URL created
@@ -253,7 +253,7 @@ module ActionView
253
253
  # # <input value="New" type="submit" />
254
254
  # # </form>"
255
255
  #
256
- # <%= button_to "New", new_article_path %>
256
+ # <%= button_to "New", new_articles_path %>
257
257
  # # => "<form method="post" action="/articles/new" class="button_to">
258
258
  # # <input value="New" type="submit" />
259
259
  # # </form>"
@@ -308,7 +308,7 @@ module ActionView
308
308
  params = html_options.delete("params")
309
309
 
310
310
  method = html_options.delete("method").to_s
311
- method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".freeze.html_safe
311
+ method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
312
312
 
313
313
  form_method = method == "get" ? "get" : "post"
314
314
  form_options = html_options.delete("form") || {}
@@ -321,7 +321,7 @@ module ActionView
321
321
  request_method = method.empty? ? "post" : method
322
322
  token_tag(nil, form_options: { action: url, method: request_method })
323
323
  else
324
- "".freeze
324
+ ""
325
325
  end
326
326
 
327
327
  html_options = convert_options_to_data_attributes(options, html_options)
@@ -487,12 +487,12 @@ module ActionView
487
487
  option = html_options.delete(item).presence || next
488
488
  "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
489
489
  }.compact
490
- extras = extras.empty? ? "".freeze : "?" + extras.join("&")
490
+ extras = extras.empty? ? "" : "?" + extras.join("&")
491
491
 
492
492
  encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
493
493
  html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
494
494
 
495
- content_tag("a".freeze, name || email_address, html_options, &block)
495
+ content_tag("a", name || email_address, html_options, &block)
496
496
  end
497
497
 
498
498
  # True if the current request URI was generated by the given +options+.
@@ -575,21 +575,21 @@ module ActionView
575
575
  def convert_options_to_data_attributes(options, html_options)
576
576
  if html_options
577
577
  html_options = html_options.stringify_keys
578
- html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
578
+ html_options["data-remote"] = "true" if link_to_remote_options?(options) || link_to_remote_options?(html_options)
579
579
 
580
- method = html_options.delete("method".freeze)
580
+ method = html_options.delete("method")
581
581
 
582
582
  add_method_to_attributes!(html_options, method) if method
583
583
 
584
584
  html_options
585
585
  else
586
- link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
586
+ link_to_remote_options?(options) ? { "data-remote" => "true" } : {}
587
587
  end
588
588
  end
589
589
 
590
590
  def link_to_remote_options?(options)
591
591
  if options.is_a?(Hash)
592
- options.delete("remote".freeze) || options.delete(:remote)
592
+ options.delete("remote") || options.delete(:remote)
593
593
  end
594
594
  end
595
595
 
@@ -618,11 +618,11 @@ module ActionView
618
618
  end
619
619
 
620
620
  def token_tag(token = nil, form_options: {})
621
- if token != false && protect_against_forgery?
621
+ if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
622
622
  token ||= form_authenticity_token(form_options: form_options)
623
623
  tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
624
624
  else
625
- "".freeze
625
+ ""
626
626
  end
627
627
  end
628
628
 
@@ -636,7 +636,7 @@ module ActionView
636
636
  # to_form_params(name: 'David', nationality: 'Danish')
637
637
  # # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
638
638
  #
639
- # to_form_params(country: {name: 'Denmark'})
639
+ # to_form_params(country: { name: 'Denmark' })
640
640
  # # => [{name: 'country[name]', value: 'Denmark'}]
641
641
  #
642
642
  # to_form_params(countries: ['Denmark', 'Sweden']})
@@ -23,7 +23,6 @@ module ActionView #:nodoc:
23
23
  autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
24
24
  autoload :NumberHelper
25
25
  autoload :OutputSafetyHelper
26
- autoload :RecordTagHelper
27
26
  autoload :RenderingHelper
28
27
  autoload :SanitizeHelper
29
28
  autoload :TagHelper
@@ -57,7 +56,6 @@ module ActionView #:nodoc:
57
56
  include JavaScriptHelper
58
57
  include NumberHelper
59
58
  include OutputSafetyHelper
60
- include RecordTagHelper
61
59
  include RenderingHelper
62
60
  include SanitizeHelper
63
61
  include TagHelper
@@ -16,17 +16,17 @@ module ActionView
16
16
 
17
17
  def render_template(event)
18
18
  info do
19
- message = " Rendered #{from_rails_root(event.payload[:identifier])}".dup
19
+ message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
20
20
  message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
21
- message << " (#{event.duration.round(1)}ms)"
21
+ message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
22
22
  end
23
23
  end
24
24
 
25
25
  def render_partial(event)
26
26
  info do
27
- message = " Rendered #{from_rails_root(event.payload[:identifier])}".dup
27
+ message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
28
28
  message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
29
- message << " (#{event.duration.round(1)}ms)"
29
+ message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
30
30
  message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
31
31
  message
32
32
  end
@@ -37,7 +37,7 @@ module ActionView
37
37
 
38
38
  info do
39
39
  " Rendered collection of #{from_rails_root(identifier)}" \
40
- " #{render_count(event.payload)} (#{event.duration.round(1)}ms)"
40
+ " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
41
41
  end
42
42
  end
43
43
 
@@ -85,7 +85,7 @@ module ActionView
85
85
 
86
86
  def log_rendering_start(payload)
87
87
  info do
88
- message = " Rendering #{from_rails_root(payload[:identifier])}".dup
88
+ message = +" Rendering #{from_rails_root(payload[:identifier])}"
89
89
  message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
90
90
  message
91
91
  end
@@ -24,7 +24,7 @@ module ActionView
24
24
  registered_details << name
25
25
  Accessors::DEFAULT_PROCS[name] = block
26
26
 
27
- Accessors.send :define_method, :"default_#{name}", &block
27
+ Accessors.define_method(:"default_#{name}", &block)
28
28
  Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
29
29
  def #{name}
30
30
  @details.fetch(:#{name}, [])
@@ -202,13 +202,13 @@ module ActionView
202
202
  # name instead of the prefix.
203
203
  def normalize_name(name, prefixes)
204
204
  prefixes = prefixes.presence
205
- parts = name.to_s.split("/".freeze)
205
+ parts = name.to_s.split("/")
206
206
  parts.shift if parts.first.empty?
207
207
  name = parts.pop
208
208
 
209
209
  return name, prefixes || [""] if parts.empty?
210
210
 
211
- parts = parts.join("/".freeze)
211
+ parts = parts.join("/")
212
212
  prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
213
213
 
214
214
  return name, prefixes
@@ -245,7 +245,7 @@ module ActionView
245
245
  # add :html as fallback to :js.
246
246
  def formats=(values)
247
247
  if values
248
- values.concat(default_formats) if values.delete "*/*".freeze
248
+ values.concat(default_formats) if values.delete "*/*"
249
249
  if values == [:js]
250
250
  values << :html
251
251
  @html_fallback_for_js = true
@@ -9,6 +9,8 @@ module ActionView
9
9
  config.action_view = ActiveSupport::OrderedOptions.new
10
10
  config.action_view.embed_authenticity_token_in_remote_forms = nil
11
11
  config.action_view.debug_missing_translation = true
12
+ config.action_view.default_enforce_utf8 = nil
13
+ config.action_view.finalize_compiled_template_methods = true
12
14
 
13
15
  config.eager_load_namespaces << ActionView
14
16
 
@@ -35,6 +37,22 @@ module ActionView
35
37
  end
36
38
  end
37
39
 
40
+ initializer "action_view.default_enforce_utf8" do |app|
41
+ ActiveSupport.on_load(:action_view) do
42
+ default_enforce_utf8 = app.config.action_view.delete(:default_enforce_utf8)
43
+ unless default_enforce_utf8.nil?
44
+ ActionView::Helpers::FormTagHelper.default_enforce_utf8 = default_enforce_utf8
45
+ end
46
+ end
47
+ end
48
+
49
+ initializer "action_view.finalize_compiled_template_methods" do |app|
50
+ ActiveSupport.on_load(:action_view) do
51
+ ActionView::Template.finalize_compiled_template_methods =
52
+ app.config.action_view.delete(:finalize_compiled_template_methods)
53
+ end
54
+ end
55
+
38
56
  initializer "action_view.logger" do
39
57
  ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
40
58
  end
@@ -59,8 +59,8 @@ module ActionView
59
59
 
60
60
  include ModelNaming
61
61
 
62
- JOIN = "_".freeze
63
- NEW = "new".freeze
62
+ JOIN = "_"
63
+ NEW = "new"
64
64
 
65
65
  # The DOM class convention is to use the singular form of an object or class.
66
66
  #