simple_form 4.0.1 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +61 -8
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +43 -52
  5. data/lib/generators/simple_form/templates/README +2 -3
  6. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +1 -7
  7. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +26 -25
  8. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +1 -1
  9. data/lib/simple_form.rb +22 -5
  10. data/lib/simple_form/components/errors.rb +5 -1
  11. data/lib/simple_form/form_builder.rb +30 -10
  12. data/lib/simple_form/inputs.rb +2 -0
  13. data/lib/simple_form/inputs/base.rb +4 -1
  14. data/lib/simple_form/inputs/boolean_input.rb +1 -0
  15. data/lib/simple_form/inputs/collection_check_boxes_input.rb +1 -1
  16. data/lib/simple_form/inputs/collection_input.rb +1 -1
  17. data/lib/simple_form/inputs/color_input.rb +14 -0
  18. data/lib/simple_form/inputs/priority_input.rb +0 -4
  19. data/lib/simple_form/inputs/rich_text_area_input.rb +12 -0
  20. data/lib/simple_form/inputs/string_input.rb +1 -1
  21. data/lib/simple_form/tags.rb +6 -2
  22. data/lib/simple_form/version.rb +1 -1
  23. data/lib/simple_form/wrappers/root.rb +8 -3
  24. data/test/action_view_extensions/builder_test.rb +22 -4
  25. data/test/form_builder/association_test.rb +6 -0
  26. data/test/form_builder/error_test.rb +6 -0
  27. data/test/form_builder/general_test.rb +23 -19
  28. data/test/form_builder/input_field_test.rb +3 -9
  29. data/test/form_builder/label_test.rb +1 -1
  30. data/test/form_builder/wrapper_test.rb +8 -1
  31. data/test/inputs/boolean_input_test.rb +8 -0
  32. data/test/inputs/collection_check_boxes_input_test.rb +8 -0
  33. data/test/inputs/collection_radio_buttons_input_test.rb +8 -0
  34. data/test/inputs/collection_select_input_test.rb +6 -0
  35. data/test/inputs/color_input_test.rb +10 -0
  36. data/test/inputs/datetime_input_test.rb +2 -12
  37. data/test/inputs/disabled_test.rb +13 -0
  38. data/test/inputs/discovery_test.rb +21 -0
  39. data/test/inputs/priority_input_test.rb +6 -14
  40. data/test/inputs/rich_text_area_input_test.rb +15 -0
  41. data/test/inputs/string_input_test.rb +8 -15
  42. data/test/support/discovery_inputs.rb +7 -0
  43. data/test/support/misc_helpers.rb +8 -2
  44. data/test/support/models.rb +29 -6
  45. data/test/test_helper.rb +7 -4
  46. metadata +40 -35
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Uncomment this and change the path if necessary to include your own
4
4
  # components.
5
- # See https://github.com/plataformatec/simple_form#custom-components to know
5
+ # See https://github.com/heartcombo/simple_form#custom-components to know
6
6
  # more about custom components.
7
7
  # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
8
8
  #
@@ -35,7 +35,18 @@ to
35
35
 
36
36
  def %{name}(wrapper_options)
37
37
 
38
- See https://github.com/plataformatec/simple_form/pull/997 for more information.
38
+ See https://github.com/heartcombo/simple_form/pull/997 for more information.
39
+ WARN
40
+
41
+ FILE_METHODS_DEPRECATION_WARN = <<-WARN
42
+ [SIMPLE_FORM] SimpleForm.file_methods is deprecated and has no effect.
43
+
44
+ Since version 5, Simple Form now supports automatically discover of file inputs for the following Gems: activestorage, carrierwave, paperclip, refile and shrine.
45
+ If you are using a custom method that is not from one of the supported Gems, please change your forms to pass the input type explicitly:
46
+
47
+ <%= form.input :avatar, as: :file %>
48
+
49
+ See http://blog.plataformatec.com.br/2019/09/incorrect-access-control-in-simple-form-cve-2019-16676 for more information.
39
50
  WARN
40
51
 
41
52
  @@configured = false
@@ -120,10 +131,6 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
120
131
  mattr_accessor :browser_validations
121
132
  @@browser_validations = true
122
133
 
123
- # Collection of methods to detect if a file type was given.
124
- mattr_accessor :file_methods
125
- @@file_methods = %i[mounted_as file? public_filename attached?]
126
-
127
134
  # Custom mappings for input types. This should be a hash containing a regexp
128
135
  # to match as key, and the input type that will be used when the field name
129
136
  # matches the regexp as value, such as { /count/ => :integer }.
@@ -265,6 +272,16 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
265
272
  @@form_class = value
266
273
  end
267
274
 
275
+ def self.file_methods=(file_methods)
276
+ ActiveSupport::Deprecation.warn(FILE_METHODS_DEPRECATION_WARN, caller)
277
+ @@file_methods = file_methods
278
+ end
279
+
280
+ def self.file_methods
281
+ ActiveSupport::Deprecation.warn(FILE_METHODS_DEPRECATION_WARN, caller)
282
+ @@file_methods
283
+ end
284
+
268
285
  # Default way to setup Simple Form. Run rails generate simple_form:install
269
286
  # to create a fresh initializer with all configuration values.
270
287
  def self.setup
@@ -11,7 +11,7 @@ module SimpleForm
11
11
  end
12
12
 
13
13
  def has_errors?
14
- object && object.respond_to?(:errors) && errors.present?
14
+ object_with_errors? || object.nil? && has_custom_error?
15
15
  end
16
16
 
17
17
  def has_value?
@@ -34,6 +34,10 @@ module SimpleForm
34
34
  has_custom_error? ? options[:error] : full_errors.send(error_method)
35
35
  end
36
36
 
37
+ def object_with_errors?
38
+ object && object.respond_to?(:errors) && errors.present?
39
+ end
40
+
37
41
  def error_method
38
42
  options[:error_method] || SimpleForm.error_method
39
43
  end
@@ -26,6 +26,7 @@ module SimpleForm
26
26
  map_type :range, to: SimpleForm::Inputs::RangeInput
27
27
  map_type :check_boxes, to: SimpleForm::Inputs::CollectionCheckBoxesInput
28
28
  map_type :radio_buttons, to: SimpleForm::Inputs::CollectionRadioButtonsInput
29
+ map_type :rich_text_area, to: SimpleForm::Inputs::RichTextAreaInput
29
30
  map_type :select, to: SimpleForm::Inputs::CollectionSelectInput
30
31
  map_type :grouped_select, to: SimpleForm::Inputs::GroupedCollectionSelectInput
31
32
  map_type :date, :time, :datetime, to: SimpleForm::Inputs::DateTimeInput
@@ -165,7 +166,7 @@ module SimpleForm
165
166
  components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS)
166
167
 
167
168
  options = options.dup
168
- options[:input_html] = options.except(:as, :boolean_style, :collection, :label_method, :value_method, :prompt, *components)
169
+ options[:input_html] = options.except(:as, :boolean_style, :collection, :disabled, :label_method, :value_method, :prompt, *components)
169
170
  options = @defaults.deep_dup.deep_merge(options) if @defaults
170
171
 
171
172
  input = find_input(attribute_name, options)
@@ -511,7 +512,7 @@ module SimpleForm
511
512
  when :has_one
512
513
  raise ArgumentError, ":has_one associations are not supported by f.association"
513
514
  else
514
- if options[:as] == :select
515
+ if options[:as] == :select || options[:as] == :grouped_select
515
516
  html_options = options[:input_html] ||= {}
516
517
  html_options[:multiple] = true unless html_options.key?(:multiple)
517
518
  end
@@ -552,12 +553,12 @@ module SimpleForm
552
553
  :datetime
553
554
  when :string, :citext, nil
554
555
  case attribute_name.to_s
555
- when /password/ then :password
556
- when /time_zone/ then :time_zone
557
- when /country/ then :country
558
- when /email/ then :email
559
- when /phone/ then :tel
560
- when /url/ then :url
556
+ when /(?:\b|\W|_)password(?:\b|\W|_)/ then :password
557
+ when /(?:\b|\W|_)time_zone(?:\b|\W|_)/ then :time_zone
558
+ when /(?:\b|\W|_)country(?:\b|\W|_)/ then :country
559
+ when /(?:\b|\W|_)email(?:\b|\W|_)/ then :email
560
+ when /(?:\b|\W|_)phone(?:\b|\W|_)/ then :tel
561
+ when /(?:\b|\W|_)url(?:\b|\W|_)/ then :url
561
562
  else
562
563
  file_method?(attribute_name) ? :file : (input_type || :string)
563
564
  end
@@ -572,9 +573,28 @@ module SimpleForm
572
573
  }.try(:last) if SimpleForm.input_mappings
573
574
  end
574
575
 
576
+ # Internal: Try to discover whether an attribute corresponds to a file or not.
577
+ #
578
+ # Most upload Gems add some kind of attributes to the ActiveRecord's model they are included in.
579
+ # This method tries to guess if an attribute belongs to some of these Gems by checking the presence
580
+ # of their methods using `#respond_to?`.
581
+ #
582
+ # Note: This does not support multiple file upload inputs, as this is very application-specific.
583
+ #
584
+ # The order here was chosen based on the popularity of Gems:
585
+ #
586
+ # - `#{attribute_name}_attachment` - ActiveStorage >= `5.2` and Refile >= `0.2.0` <= `0.4.0`
587
+ # - `remote_#{attribute_name}_url` - Refile >= `0.3.0` and CarrierWave >= `0.2.2`
588
+ # - `#{attribute_name}_attacher` - Refile >= `0.4.0` and Shrine >= `0.9.0`
589
+ # - `#{attribute_name}_file_name` - Paperclip ~> `2.0` (added for backwards compatibility)
590
+ #
591
+ # Returns a Boolean.
575
592
  def file_method?(attribute_name)
576
- file = @object.send(attribute_name) if @object.respond_to?(attribute_name)
577
- file && SimpleForm.file_methods.any? { |m| file.respond_to?(m) }
593
+ @object.respond_to?("#{attribute_name}_attachment") ||
594
+ @object.respond_to?("#{attribute_name}_attachments") ||
595
+ @object.respond_to?("remote_#{attribute_name}_url") ||
596
+ @object.respond_to?("#{attribute_name}_attacher") ||
597
+ @object.respond_to?("#{attribute_name}_file_name")
578
598
  end
579
599
 
580
600
  def find_attribute_column(attribute_name)
@@ -10,6 +10,7 @@ module SimpleForm
10
10
  autoload :CollectionInput
11
11
  autoload :CollectionRadioButtonsInput
12
12
  autoload :CollectionSelectInput
13
+ autoload :ColorInput
13
14
  autoload :DateTimeInput
14
15
  autoload :FileInput
15
16
  autoload :GroupedCollectionSelectInput
@@ -18,6 +19,7 @@ module SimpleForm
18
19
  autoload :PasswordInput
19
20
  autoload :PriorityInput
20
21
  autoload :RangeInput
22
+ autoload :RichTextAreaInput
21
23
  autoload :StringInput
22
24
  autoload :TextInput
23
25
  end
@@ -72,7 +72,10 @@ module SimpleForm
72
72
  @html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
73
73
 
74
74
  @input_html_classes = @html_classes.dup
75
- if SimpleForm.input_class && !input_html_classes.empty?
75
+
76
+ input_html_classes = self.input_html_classes
77
+
78
+ if SimpleForm.input_class && input_html_classes.any?
76
79
  input_html_classes << SimpleForm.input_class
77
80
  end
78
81
 
@@ -63,6 +63,7 @@ module SimpleForm
63
63
  return "" if !include_hidden? || !unchecked_value
64
64
  options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
65
65
  options[:name] = input_html_options[:name] if input_html_options.key?(:name)
66
+ options[:form] = input_html_options[:form] if input_html_options.key?(:form)
66
67
 
67
68
  @builder.hidden_field(attribute_name, options)
68
69
  end
@@ -5,7 +5,7 @@ module SimpleForm
5
5
  protected
6
6
 
7
7
  # Checkbox components do not use the required html tag.
8
- # More info: https://github.com/plataformatec/simple_form/issues/340#issuecomment-2871956
8
+ # More info: https://github.com/heartcombo/simple_form/issues/340#issuecomment-2871956
9
9
  def has_required?
10
10
  false
11
11
  end
@@ -41,7 +41,7 @@ module SimpleForm
41
41
  end
42
42
 
43
43
  def has_required?
44
- super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
44
+ super && (input_options[:include_blank] || input_options[:prompt].present? || multiple?)
45
45
  end
46
46
 
47
47
  # Check if :include_blank must be included by default.
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module SimpleForm
3
+ module Inputs
4
+ class ColorInput < Base
5
+ def input(wrapper_options = nil)
6
+ input_html_options[:type] ||= "color" if html5?
7
+
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.text_field(attribute_name, merged_input_options)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -15,10 +15,6 @@ module SimpleForm
15
15
 
16
16
  protected
17
17
 
18
- def has_required?
19
- false
20
- end
21
-
22
18
  def skip_include_blank?
23
19
  super || input_priority.present?
24
20
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module SimpleForm
3
+ module Inputs
4
+ class RichTextAreaInput < Base
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
8
+ @builder.rich_text_area(attribute_name, merged_input_options)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -18,7 +18,7 @@ module SimpleForm
18
18
  private
19
19
 
20
20
  def string?
21
- input_type == :string
21
+ input_type == :string || input_type == :citext
22
22
  end
23
23
  end
24
24
  end
@@ -48,7 +48,9 @@ module SimpleForm
48
48
  private
49
49
 
50
50
  def render_component(builder)
51
- builder.radio_button + builder.label(class: "collection_radio_buttons")
51
+ label_class = "#{@options[:item_label_class]} collection_radio_buttons".strip
52
+
53
+ builder.radio_button + builder.label(class: label_class)
52
54
  end
53
55
  end
54
56
 
@@ -62,7 +64,9 @@ module SimpleForm
62
64
  private
63
65
 
64
66
  def render_component(builder)
65
- builder.check_box + builder.label(class: "collection_check_boxes")
67
+ label_class = "#{@options[:item_label_class]} collection_check_boxes".strip
68
+
69
+ builder.check_box + builder.label(class: label_class)
66
70
  end
67
71
  end
68
72
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module SimpleForm
3
- VERSION = "4.0.1".freeze
3
+ VERSION = "5.0.3".freeze
4
4
  end
@@ -28,11 +28,16 @@ module SimpleForm
28
28
  css += SimpleForm.additional_classes_for(:wrapper) do
29
29
  input.additional_classes + [input.input_class]
30
30
  end
31
- css << (options[:wrapper_error_class] || @defaults[:error_class]) if input.has_errors?
32
- css << (options[:wrapper_hint_class] || @defaults[:hint_class]) if input.has_hint?
33
- css << (options[:wrapper_valid_class] || @defaults[:valid_class]) if input.valid?
31
+ css << html_class(:error_class, options) { input.has_errors? }
32
+ css << html_class(:hint_class, options) { input.has_hint? }
33
+ css << html_class(:valid_class, options) { input.valid? }
34
34
  css.compact
35
35
  end
36
+
37
+ def html_class(key, options)
38
+ css = (options[:"wrapper_#{key}"] || @defaults[key])
39
+ css if css && yield
40
+ end
36
41
  end
37
42
  end
38
43
  end
@@ -45,8 +45,17 @@ class BuilderTest < ActionView::TestCase
45
45
 
46
46
  test "collection radio sanitizes collection values for labels correctly" do
47
47
  with_collection_radio_buttons @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
48
- assert_select 'label.collection_radio_buttons[for=user_name_099]', '$0.99'
49
- assert_select 'label.collection_radio_buttons[for=user_name_199]', '$1.99'
48
+
49
+ # Rails 6 changed the way it sanitizes the values
50
+ # https://github.com/rails/rails/blob/6-0-stable/actionview/lib/action_view/helpers/tags/base.rb#L141
51
+ # https://github.com/rails/rails/blob/5-2-stable/actionview/lib/action_view/helpers/tags/base.rb#L141
52
+ if ActionView::VERSION::MAJOR == 5
53
+ assert_select 'label.collection_radio_buttons[for=user_name_099]', '$0.99'
54
+ assert_select 'label.collection_radio_buttons[for=user_name_199]', '$1.99'
55
+ else
56
+ assert_select 'label.collection_radio_buttons[for=user_name_0_99]', '$0.99'
57
+ assert_select 'label.collection_radio_buttons[for=user_name_1_99]', '$1.99'
58
+ end
50
59
  end
51
60
 
52
61
  test "collection radio checks the correct value to local variables" do
@@ -292,8 +301,17 @@ class BuilderTest < ActionView::TestCase
292
301
 
293
302
  test "collection check box sanitizes collection values for labels correctly" do
294
303
  with_collection_check_boxes @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
295
- assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99'
296
- assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99'
304
+
305
+ # Rails 6 changed the way it sanitizes the values
306
+ # https://github.com/rails/rails/blob/6-0-stable/actionview/lib/action_view/helpers/tags/base.rb#L141
307
+ # https://github.com/rails/rails/blob/5-2-stable/actionview/lib/action_view/helpers/tags/base.rb#L141
308
+ if ActionView::VERSION::MAJOR == 5
309
+ assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99'
310
+ assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99'
311
+ else
312
+ assert_select 'label.collection_check_boxes[for=user_name_0_99]', '$0.99'
313
+ assert_select 'label.collection_check_boxes[for=user_name_1_99]', '$1.99'
314
+ end
297
315
  end
298
316
 
299
317
  test "collection check box checks the correct value to local variables" do
@@ -243,4 +243,10 @@ class AssociationTest < ActionView::TestCase
243
243
  assert_equal({ as: :check_boxes, collection_wrapper_tag: :ul, item_wrapper_tag: :li },
244
244
  options)
245
245
  end
246
+
247
+ test 'builder with group select considers multiple select by default' do
248
+ with_association_for @user, :tags, as: :grouped_select, group_method: :group_method
249
+
250
+ assert_select 'select[multiple="multiple"].grouped_select'
251
+ end
246
252
  end
@@ -224,6 +224,12 @@ class ErrorTest < ActionView::TestCase
224
224
  assert_no_select 'span.error'
225
225
  end
226
226
 
227
+ test 'input with custom error works when form does not use a model' do
228
+ with_form_for :user, :active, error: "Super User Active! cannot be blank"
229
+
230
+ assert_select 'span.error'
231
+ end
232
+
227
233
  test 'input with custom error works when using full_error component' do
228
234
  swap_wrapper :default, custom_wrapper_with_full_error do
229
235
  error_text = "Super User Name! cannot be blank"
@@ -239,31 +239,29 @@ class FormBuilderTest < ActionView::TestCase
239
239
  assert_select 'form select#user_updated_at_1i.datetime'
240
240
  end
241
241
 
242
- test 'builder generates file for file columns' do
243
- @user.avatar = MiniTest::Mock.new
244
- @user.avatar.expect(:public_filename, true)
245
- @user.avatar.expect(:!, false)
246
-
247
- with_form_for @user, :avatar
248
- assert_select 'form input#user_avatar.file'
242
+ test 'builder generates file input for ActiveStorage >= 5.2 and Refile >= 0.2.0 <= 0.4.0' do
243
+ with_form_for UserWithAttachment.build, :avatar
244
+ assert_select 'form input#user_with_attachment_avatar.file'
249
245
  end
250
246
 
251
- test 'builder generates file for activestorage entries' do
252
- @user.avatar = MiniTest::Mock.new
253
- @user.avatar.expect(:attached?, false)
254
- @user.avatar.expect(:!, false)
247
+ test 'builder generates file input for ActiveStorage::Attached::Many' do
248
+ with_form_for UserWithAttachment.build, :avatars
249
+ assert_select 'form input#user_with_attachment_avatars.file'
250
+ end
255
251
 
256
- with_form_for @user, :avatar
257
- assert_select 'form input#user_avatar.file'
252
+ test 'builder generates file input for Refile >= 0.3.0 and CarrierWave >= 0.2.2' do
253
+ with_form_for UserWithAttachment.build, :cover
254
+ assert_select 'form input#user_with_attachment_cover.file'
258
255
  end
259
256
 
260
- test 'builder generates file for attributes that are real db columns but have file methods' do
261
- @user.home_picture = MiniTest::Mock.new
262
- @user.home_picture.expect(:mounted_as, true)
263
- @user.home_picture.expect(:!, false)
257
+ test 'builder generates file input for Refile >= 0.4.0 and Shrine >= 0.9.0' do
258
+ with_form_for UserWithAttachment.build, :profile_image
259
+ assert_select 'form input#user_with_attachment_profile_image.file'
260
+ end
264
261
 
265
- with_form_for @user, :home_picture
266
- assert_select 'form input#user_home_picture.file'
262
+ test 'builder generates file input for Paperclip ~> 2.0' do
263
+ with_form_for UserWithAttachment.build, :portrait
264
+ assert_select 'form input#user_with_attachment_portrait.file'
267
265
  end
268
266
 
269
267
  test 'build generates select if a collection is given' do
@@ -271,6 +269,12 @@ class FormBuilderTest < ActionView::TestCase
271
269
  assert_select 'form select#user_age.select'
272
270
  end
273
271
 
272
+ test 'builder does not generate url fields for columns that contain only the letters url' do
273
+ with_form_for @user, :hourly
274
+ assert_no_select 'form input#user_url.string.url'
275
+ assert_select 'form input#user_hourly.string'
276
+ end
277
+
274
278
  test 'builder allows overriding default input type for text' do
275
279
  with_form_for @user, :name, as: :text
276
280
  assert_no_select 'form input#user_name'
@@ -3,12 +3,6 @@ require 'test_helper'
3
3
 
4
4
  # Tests for f.input_field
5
5
  class InputFieldTest < ActionView::TestCase
6
- def with_input_field_for(object, *args)
7
- with_concat_form_for(object) do |f|
8
- f.input_field(*args)
9
- end
10
- end
11
-
12
6
  test "builder input_field only renders the input tag, nothing else" do
13
7
  with_input_field_for @user, :name
14
8
 
@@ -85,13 +79,13 @@ class InputFieldTest < ActionView::TestCase
85
79
  test 'builder input_field infers pattern from attributes' do
86
80
  with_input_field_for @other_validating_user, :country, as: :string, pattern: true
87
81
 
88
- assert_select 'input[pattern="\w+"]'
82
+ assert_select "input:match('pattern', ?)", /\w+/
89
83
  end
90
84
 
91
85
  test 'builder input_field accepts custom pattern' do
92
86
  with_input_field_for @other_validating_user, :country, as: :string, pattern: '\d+'
93
87
 
94
- assert_select 'input[pattern="\d+"]'
88
+ assert_select "input:match('pattern', ?)", /\\d+/
95
89
  end
96
90
 
97
91
  test 'builder input_field uses readonly component' do
@@ -138,7 +132,7 @@ class InputFieldTest < ActionView::TestCase
138
132
  swap_wrapper :default, custom_wrapper_with_html5_components do
139
133
  with_input_field_for @user, :name, pattern: '\w+'
140
134
 
141
- assert_select 'input[pattern="\w+"]'
135
+ assert_select "input:match('pattern', ?)", /\w+/
142
136
  end
143
137
  end
144
138