actionview 4.1.16 → 4.2.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +85 -483
  3. data/README.rdoc +7 -2
  4. data/lib/action_view.rb +0 -1
  5. data/lib/action_view/base.rb +2 -10
  6. data/lib/action_view/digestor.rb +1 -1
  7. data/lib/action_view/gem_version.rb +3 -3
  8. data/lib/action_view/helpers/asset_tag_helper.rb +32 -25
  9. data/lib/action_view/helpers/asset_url_helper.rb +29 -18
  10. data/lib/action_view/helpers/cache_helper.rb +2 -2
  11. data/lib/action_view/helpers/capture_helper.rb +1 -12
  12. data/lib/action_view/helpers/date_helper.rb +16 -12
  13. data/lib/action_view/helpers/debug_helper.rb +7 -11
  14. data/lib/action_view/helpers/form_helper.rb +65 -13
  15. data/lib/action_view/helpers/form_options_helper.rb +3 -3
  16. data/lib/action_view/helpers/form_tag_helper.rb +137 -28
  17. data/lib/action_view/helpers/javascript_helper.rb +7 -1
  18. data/lib/action_view/helpers/number_helper.rb +8 -10
  19. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  20. data/lib/action_view/helpers/rendering_helper.rb +6 -6
  21. data/lib/action_view/helpers/sanitize_helper.rb +67 -109
  22. data/lib/action_view/helpers/tag_helper.rb +15 -5
  23. data/lib/action_view/helpers/tags/base.rb +1 -1
  24. data/lib/action_view/helpers/tags/collection_check_boxes.rb +5 -1
  25. data/lib/action_view/helpers/tags/collection_helpers.rb +1 -1
  26. data/lib/action_view/helpers/tags/datetime_field.rb +10 -2
  27. data/lib/action_view/helpers/tags/label.rb +3 -3
  28. data/lib/action_view/helpers/tags/placeholderable.rb +32 -0
  29. data/lib/action_view/helpers/tags/text_area.rb +4 -0
  30. data/lib/action_view/helpers/tags/text_field.rb +4 -1
  31. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  32. data/lib/action_view/helpers/text_helper.rb +25 -8
  33. data/lib/action_view/helpers/translation_helper.rb +29 -25
  34. data/lib/action_view/helpers/url_helper.rb +13 -14
  35. data/lib/action_view/log_subscriber.rb +5 -5
  36. data/lib/action_view/lookup_context.rb +6 -12
  37. data/lib/action_view/model_naming.rb +1 -1
  38. data/lib/action_view/path_set.rb +7 -19
  39. data/lib/action_view/renderer/abstract_renderer.rb +5 -3
  40. data/lib/action_view/renderer/partial_renderer.rb +76 -38
  41. data/lib/action_view/renderer/renderer.rb +0 -4
  42. data/lib/action_view/renderer/template_renderer.rb +5 -6
  43. data/lib/action_view/rendering.rb +7 -6
  44. data/lib/action_view/routing_url_for.rb +13 -5
  45. data/lib/action_view/tasks/dependencies.rake +7 -9
  46. data/lib/action_view/template/handlers.rb +9 -0
  47. data/lib/action_view/template/resolver.rb +7 -24
  48. data/lib/action_view/test_case.rb +13 -7
  49. data/lib/action_view/testing/resolvers.rb +2 -2
  50. data/lib/action_view/view_paths.rb +26 -15
  51. metadata +52 -18
  52. data/lib/action_view/vendor/html-scanner.rb +0 -20
  53. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  54. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  55. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  56. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  57. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  58. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
@@ -47,7 +47,13 @@ module ActionView
47
47
  # tag.
48
48
  #
49
49
  # javascript_tag "alert('All is good')", defer: 'defer'
50
- # # => <script defer="defer">alert('All is good')</script>
50
+ #
51
+ # Returns:
52
+ # <script defer="defer">
53
+ # //<![CDATA[
54
+ # alert('All is good')
55
+ # //]]>
56
+ # </script>
51
57
  #
52
58
  # Instead of passing the content as an argument, you can also use a block
53
59
  # in which case, you pass your +html_options+ as the first parameter.
@@ -266,14 +266,8 @@ module ActionView
266
266
  # number_to_human_size(1234567, precision: 2) # => 1.2 MB
267
267
  # number_to_human_size(483989, precision: 2) # => 470 KB
268
268
  # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
269
- #
270
- # Non-significant zeros after the fractional separator are
271
- # stripped out by default (set
272
- # <tt>:strip_insignificant_zeros</tt> to +false+ to change
273
- # that):
274
- #
275
- # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
276
- # number_to_human_size(524288000, precision: 5) # => "500 MB"
269
+ # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
270
+ # number_to_human_size(524288000, precision: 5) # => "500 MB"
277
271
  def number_to_human_size(number, options = {})
278
272
  delegate_number_helper_method(:number_to_human_size, number, options)
279
273
  end
@@ -343,11 +337,15 @@ module ActionView
343
337
  # separator: ',',
344
338
  # significant: false) # => "1,2 Million"
345
339
  #
340
+ # number_to_human(500000000, precision: 5) # => "500 Million"
341
+ # number_to_human(12345012345, significant: false) # => "12.345 Billion"
342
+ #
346
343
  # Non-significant zeros after the decimal separator are stripped
347
344
  # out by default (set <tt>:strip_insignificant_zeros</tt> to
348
345
  # +false+ to change that):
349
- # number_to_human(12345012345, significant_digits: 6) # => "12.345 Billion"
350
- # number_to_human(500000000, precision: 5) # => "500 Million"
346
+ #
347
+ # number_to_human(12.00001) # => "12"
348
+ # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
351
349
  #
352
350
  # ==== Custom Unit Quantifiers
353
351
  #
@@ -17,10 +17,10 @@ module ActionView #:nodoc:
17
17
  stringish.to_s.html_safe
18
18
  end
19
19
 
20
- # This method returns a html safe string similar to what <tt>Array#join</tt>
21
- # would return. All items in the array, including the supplied separator, are
22
- # html escaped unless they are html safe, and the returned string is marked
23
- # as html safe.
20
+ # This method returns an HTML safe string similar to what <tt>Array#join</tt>
21
+ # would return. The array is flattened, and all items, including
22
+ # the supplied separator, are HTML escaped unless they are HTML
23
+ # safe, and the returned string is marked as HTML safe.
24
24
  #
25
25
  # safe_join(["<p>foo</p>".html_safe, "<p>bar</p>"], "<br />")
26
26
  # # => "<p>foo</p>&lt;br /&gt;&lt;p&gt;bar&lt;/p&gt;"
@@ -29,9 +29,9 @@ module ActionView #:nodoc:
29
29
  # # => "<p>foo</p><br /><p>bar</p>"
30
30
  #
31
31
  def safe_join(array, sep=$,)
32
- sep = ERB::Util.html_escape(sep)
32
+ sep = ERB::Util.unwrapped_html_escape(sep)
33
33
 
34
- array.map { |i| ERB::Util.html_escape(i) }.join(sep).html_safe
34
+ array.flatten.map! { |i| ERB::Util.unwrapped_html_escape(i) }.join(sep).html_safe
35
35
  end
36
36
  end
37
37
  end
@@ -13,13 +13,13 @@ module ActionView
13
13
  # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
14
14
  # * <tt>:text</tt> - Renders the text passed in out.
15
15
  # * <tt>:plain</tt> - Renders the text passed in out. Setting the content
16
- # type as <tt>text/plain</tt>.
17
- # * <tt>:html</tt> - Renders the html safe string passed in out, otherwise
18
- # performs html escape on the string first. Setting the content type as
19
- # <tt>text/html</tt>.
16
+ # type as <tt>text/plain</tt>.
17
+ # * <tt>:html</tt> - Renders the HTML safe string passed in out, otherwise
18
+ # performs HTML escape on the string first. Setting the content type as
19
+ # <tt>text/html</tt>.
20
20
  # * <tt>:body</tt> - Renders the text passed in, and inherits the content
21
- # type of <tt>text/html</tt> from <tt>ActionDispatch::Response</tt>
22
- # object.
21
+ # type of <tt>text/html</tt> from <tt>ActionDispatch::Response</tt>
22
+ # object.
23
23
  #
24
24
  # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
25
25
  # as the locals hash.
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/object/try'
2
- require 'action_view/vendor/html-scanner'
2
+ require 'active_support/deprecation'
3
+ require 'rails-deprecated_sanitizer'
3
4
 
4
5
  module ActionView
5
6
  # = Action View Sanitize Helpers
@@ -8,7 +9,7 @@ module ActionView
8
9
  # These helper methods extend Action View making them callable within your template files.
9
10
  module SanitizeHelper
10
11
  extend ActiveSupport::Concern
11
- # This +sanitize+ helper will html encode all tags and strip all attributes that
12
+ # This +sanitize+ helper will HTML encode all tags and strip all attributes that
12
13
  # aren't specifically allowed.
13
14
  #
14
15
  # It also strips href/src tags with invalid protocols, like javascript: especially.
@@ -27,14 +28,36 @@ module ActionView
27
28
  #
28
29
  # <%= sanitize @article.body %>
29
30
  #
30
- # Custom Use (only the mentioned tags and attributes are allowed, nothing else)
31
+ # Custom Use - Custom Scrubber
32
+ # (supply a Loofah::Scrubber that does the sanitization)
33
+ #
34
+ # scrubber can either wrap a block:
35
+ # scrubber = Loofah::Scrubber.new do |node|
36
+ # node.text = "dawn of cats"
37
+ # end
38
+ #
39
+ # or be a subclass of Loofah::Scrubber which responds to scrub:
40
+ # class KittyApocalypse < Loofah::Scrubber
41
+ # def scrub(node)
42
+ # node.text = "dawn of cats"
43
+ # end
44
+ # end
45
+ # scrubber = KittyApocalypse.new
46
+ #
47
+ # <%= sanitize @article.body, scrubber: scrubber %>
48
+ #
49
+ # A custom scrubber takes precedence over custom tags and attributes
50
+ # Learn more about scrubbers here: https://github.com/flavorjones/loofah
51
+ #
52
+ # Custom Use - tags and attributes
53
+ # (only the mentioned tags and attributes are allowed, nothing else)
31
54
  #
32
55
  # <%= sanitize @article.body, tags: %w(table tr td), attributes: %w(id class style) %>
33
56
  #
34
57
  # Add table tags to the default allowed tags
35
58
  #
36
59
  # class Application < Rails::Application
37
- # config.action_view.sanitized_allowed_tags = ['table', 'tr', 'td']
60
+ # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
38
61
  # end
39
62
  #
40
63
  # Remove tags to the default allowed tags
@@ -65,9 +88,9 @@ module ActionView
65
88
  self.class.white_list_sanitizer.sanitize_css(style)
66
89
  end
67
90
 
68
- # Strips all HTML tags from the +html+, including comments. This uses the
69
- # html-scanner tokenizer and so its HTML parsing ability is limited by
70
- # that of html-scanner.
91
+ # Strips all HTML tags from the +html+, including comments. This uses
92
+ # Nokogiri for tokenization (via Loofah) and so its HTML parsing ability
93
+ # is limited by that of Nokogiri.
71
94
  #
72
95
  # strip_tags("Strip <i>these</i> tags!")
73
96
  # # => Strip these tags!
@@ -98,47 +121,42 @@ module ActionView
98
121
  module ClassMethods #:nodoc:
99
122
  attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
100
123
 
101
- def sanitized_protocol_separator
102
- white_list_sanitizer.protocol_separator
103
- end
124
+ [:protocol_separator,
125
+ :uri_attributes,
126
+ :bad_tags,
127
+ :allowed_css_properties,
128
+ :allowed_css_keywords,
129
+ :shorthand_css_properties,
130
+ :allowed_protocols].each do |meth|
131
+ meth_name = "sanitized_#{meth}"
132
+ imp = lambda do |name|
133
+ ActiveSupport::Deprecation.warn("#{name} is deprecated and has no effect.")
134
+ end
104
135
 
105
- def sanitized_uri_attributes
106
- white_list_sanitizer.uri_attributes
136
+ define_method(meth_name) { imp.(meth_name) }
137
+ define_method("#{meth_name}=") { |value| imp.("#{meth_name}=") }
107
138
  end
108
139
 
109
- def sanitized_bad_tags
110
- white_list_sanitizer.bad_tags
140
+ # Vendors the full, link and white list sanitizers.
141
+ # This uses html-scanner for the HTML sanitization.
142
+ # In the next Rails version this will use Rails::Html::Sanitizer instead.
143
+ # To get this new behavior now, in your Gemfile, add:
144
+ #
145
+ # gem 'rails-html-sanitizer'
146
+ #
147
+ def sanitizer_vendor
148
+ Rails::DeprecatedSanitizer
111
149
  end
112
150
 
113
151
  def sanitized_allowed_tags
114
- white_list_sanitizer.allowed_tags
152
+ sanitizer_vendor.white_list_sanitizer.allowed_tags
115
153
  end
116
154
 
117
155
  def sanitized_allowed_attributes
118
- white_list_sanitizer.allowed_attributes
119
- end
120
-
121
- def sanitized_allowed_css_properties
122
- white_list_sanitizer.allowed_css_properties
123
- end
124
-
125
- def sanitized_allowed_css_keywords
126
- white_list_sanitizer.allowed_css_keywords
127
- end
128
-
129
- def sanitized_shorthand_css_properties
130
- white_list_sanitizer.shorthand_css_properties
156
+ sanitizer_vendor.white_list_sanitizer.allowed_attributes
131
157
  end
132
158
 
133
- def sanitized_allowed_protocols
134
- white_list_sanitizer.allowed_protocols
135
- end
136
-
137
- def sanitized_protocol_separator=(value)
138
- white_list_sanitizer.protocol_separator = value
139
- end
140
-
141
- # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
159
+ # Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
142
160
  # any object that responds to +sanitize+.
143
161
  #
144
162
  # class Application < Rails::Application
@@ -146,21 +164,21 @@ module ActionView
146
164
  # end
147
165
  #
148
166
  def full_sanitizer
149
- @full_sanitizer ||= HTML::FullSanitizer.new
167
+ @full_sanitizer ||= sanitizer_vendor.full_sanitizer.new
150
168
  end
151
169
 
152
- # Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with
153
- # any object that responds to +sanitize+.
170
+ # Gets the Rails::Html::LinkSanitizer instance used by +strip_links+.
171
+ # Replace with any object that responds to +sanitize+.
154
172
  #
155
173
  # class Application < Rails::Application
156
174
  # config.action_view.link_sanitizer = MySpecialSanitizer.new
157
175
  # end
158
176
  #
159
177
  def link_sanitizer
160
- @link_sanitizer ||= HTML::LinkSanitizer.new
178
+ @link_sanitizer ||= sanitizer_vendor.link_sanitizer.new
161
179
  end
162
180
 
163
- # Gets the HTML::WhiteListSanitizer instance used by sanitize and +sanitize_css+.
181
+ # Gets the Rails::Html::WhiteListSanitizer instance used by sanitize and +sanitize_css+.
164
182
  # Replace with any object that responds to +sanitize+.
165
183
  #
166
184
  # class Application < Rails::Application
@@ -168,87 +186,27 @@ module ActionView
168
186
  # end
169
187
  #
170
188
  def white_list_sanitizer
171
- @white_list_sanitizer ||= HTML::WhiteListSanitizer.new
172
- end
173
-
174
- # Adds valid HTML attributes that the +sanitize+ helper checks for URIs.
175
- #
176
- # class Application < Rails::Application
177
- # config.action_view.sanitized_uri_attributes = ['lowsrc', 'target']
178
- # end
179
- #
180
- def sanitized_uri_attributes=(attributes)
181
- HTML::WhiteListSanitizer.uri_attributes.merge(attributes)
189
+ @white_list_sanitizer ||= sanitizer_vendor.white_list_sanitizer.new
182
190
  end
183
191
 
184
- # Adds to the Set of 'bad' tags for the +sanitize+ helper.
192
+ # Replaces the allowed tags for the +sanitize+ helper.
185
193
  #
186
194
  # class Application < Rails::Application
187
- # config.action_view.sanitized_bad_tags = ['embed', 'object']
195
+ # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
188
196
  # end
189
197
  #
190
- def sanitized_bad_tags=(attributes)
191
- HTML::WhiteListSanitizer.bad_tags.merge(attributes)
198
+ def sanitized_allowed_tags=(tags)
199
+ sanitizer_vendor.white_list_sanitizer.allowed_tags = tags
192
200
  end
193
201
 
194
- # Adds to the Set of allowed tags for the +sanitize+ helper.
195
- #
196
- # class Application < Rails::Application
197
- # config.action_view.sanitized_allowed_tags = ['table', 'tr', 'td']
198
- # end
199
- #
200
- def sanitized_allowed_tags=(attributes)
201
- HTML::WhiteListSanitizer.allowed_tags.merge(attributes)
202
- end
203
-
204
- # Adds to the Set of allowed HTML attributes for the +sanitize+ helper.
202
+ # Replaces the allowed HTML attributes for the +sanitize+ helper.
205
203
  #
206
204
  # class Application < Rails::Application
207
205
  # config.action_view.sanitized_allowed_attributes = ['onclick', 'longdesc']
208
206
  # end
209
207
  #
210
208
  def sanitized_allowed_attributes=(attributes)
211
- HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
212
- end
213
-
214
- # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ helpers.
215
- #
216
- # class Application < Rails::Application
217
- # config.action_view.sanitized_allowed_css_properties = ['expression']
218
- # end
219
- #
220
- def sanitized_allowed_css_properties=(attributes)
221
- HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes)
222
- end
223
-
224
- # Adds to the Set of allowed CSS keywords for the +sanitize+ and +sanitize_css+ helpers.
225
- #
226
- # class Application < Rails::Application
227
- # config.action_view.sanitized_allowed_css_keywords = ['expression']
228
- # end
229
- #
230
- def sanitized_allowed_css_keywords=(attributes)
231
- HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes)
232
- end
233
-
234
- # Adds to the Set of allowed shorthand CSS properties for the +sanitize+ and +sanitize_css+ helpers.
235
- #
236
- # class Application < Rails::Application
237
- # config.action_view.sanitized_shorthand_css_properties = ['expression']
238
- # end
239
- #
240
- def sanitized_shorthand_css_properties=(attributes)
241
- HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes)
242
- end
243
-
244
- # Adds to the Set of allowed protocols for the +sanitize+ helper.
245
- #
246
- # class Application < Rails::Application
247
- # config.action_view.sanitized_allowed_protocols = ['ssh', 'feed']
248
- # end
249
- #
250
- def sanitized_allowed_protocols=(attributes)
251
- HTML::WhiteListSanitizer.allowed_protocols.merge(attributes)
209
+ sanitizer_vendor.white_list_sanitizer.allowed_attributes = attributes
252
210
  end
253
211
  end
254
212
  end
@@ -9,6 +9,7 @@ module ActionView
9
9
  module TagHelper
10
10
  extend ActiveSupport::Concern
11
11
  include CaptureHelper
12
+ include OutputSafetyHelper
12
13
 
13
14
  BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
14
15
  autoplay controls loop selected hidden scoped async
@@ -42,7 +43,8 @@ module ActionView
42
43
  # For example, a key +user_id+ would render as <tt>data-user-id</tt> and
43
44
  # thus accessed as <tt>dataset.userId</tt>.
44
45
  #
45
- # Values are encoded to JSON, with the exception of strings and symbols.
46
+ # Values are encoded to JSON, with the exception of strings, symbols and
47
+ # BigDecimals.
46
48
  # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt>
47
49
  # from 1.4.3.
48
50
  #
@@ -56,6 +58,9 @@ module ActionView
56
58
  # tag("input", type: 'text', disabled: true)
57
59
  # # => <input type="text" disabled="disabled" />
58
60
  #
61
+ # tag("input", type: 'text', class: ["strong", "highlight"])
62
+ # # => <input class="strong highlight" type="text" />
63
+ #
59
64
  # tag("img", src: "open & shut.png")
60
65
  # # => <img src="open &amp; shut.png" />
61
66
  #
@@ -75,7 +80,7 @@ module ActionView
75
80
  # Set escape to false to disable attribute value escaping.
76
81
  #
77
82
  # ==== Options
78
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
83
+ # The +options+ hash can be used with attributes with no value like (<tt>disabled</tt> and
79
84
  # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
80
85
  # symbols or strings for the attribute names.
81
86
  #
@@ -84,6 +89,8 @@ module ActionView
84
89
  # # => <p>Hello world!</p>
85
90
  # content_tag(:div, content_tag(:p, "Hello world!"), class: "strong")
86
91
  # # => <div class="strong"><p>Hello world!</p></div>
92
+ # content_tag(:div, "Hello world!", class: ["strong", "highlight"])
93
+ # # => <div class="strong highlight">Hello world!</div>
87
94
  # content_tag("select", options, multiple: true)
88
95
  # # => <select multiple="multiple">...options...</select>
89
96
  #
@@ -133,7 +140,7 @@ module ActionView
133
140
 
134
141
  def content_tag_string(name, content, options, escape = true)
135
142
  tag_options = tag_options(options, escape) if options
136
- content = ERB::Util.h(content) if escape
143
+ content = ERB::Util.unwrapped_html_escape(content) if escape
137
144
  "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name.to_sym]}#{content}</#{name}>".html_safe
138
145
  end
139
146
 
@@ -167,8 +174,11 @@ module ActionView
167
174
  end
168
175
 
169
176
  def tag_option(key, value, escape)
170
- value = value.join(" ") if value.is_a?(Array)
171
- value = ERB::Util.h(value) if escape
177
+ if value.is_a?(Array)
178
+ value = escape ? safe_join(value, " ") : value.join(" ")
179
+ else
180
+ value = escape ? ERB::Util.unwrapped_html_escape(value) : value
181
+ end
172
182
  %(#{key}="#{value}")
173
183
  end
174
184
  end
@@ -25,7 +25,7 @@ module ActionView
25
25
  private
26
26
 
27
27
  def value(object)
28
- object.public_send @method_name if object
28
+ object.send @method_name if object
29
29
  end
30
30
 
31
31
  def value_before_type_cast(object)
@@ -27,7 +27,11 @@ module ActionView
27
27
 
28
28
  # Append a hidden field to make sure something will be sent back to the
29
29
  # server if all check boxes are unchecked.
30
- rendered_collection + hidden_field
30
+ if @options.fetch(:include_hidden, true)
31
+ rendered_collection + hidden_field
32
+ else
33
+ rendered_collection
34
+ end
31
35
  end
32
36
 
33
37
  private
@@ -44,7 +44,7 @@ module ActionView
44
44
  def default_html_options_for_collection(item, value) #:nodoc:
45
45
  html_options = @html_options.dup
46
46
 
47
- [:checked, :selected, :disabled].each do |option|
47
+ [:checked, :selected, :disabled, :readonly].each do |option|
48
48
  current_value = @options[option]
49
49
  next if current_value.nil?
50
50