simple_form 3.5.1 → 4.0.0
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 simple_form might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +165 -3
- data/lib/generators/simple_form/templates/README +3 -3
- data/lib/generators/simple_form/templates/_form.html.erb +1 -0
- data/lib/generators/simple_form/templates/_form.html.haml +1 -0
- data/lib/generators/simple_form/templates/_form.html.slim +1 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +14 -2
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +357 -73
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +16 -5
- data/lib/simple_form.rb +51 -2
- data/lib/simple_form/components/errors.rb +8 -0
- data/lib/simple_form/components/labels.rb +9 -3
- data/lib/simple_form/components/maxlength.rb +3 -13
- data/lib/simple_form/components/minlength.rb +3 -13
- data/lib/simple_form/components/placeholders.rb +1 -1
- data/lib/simple_form/form_builder.rb +65 -16
- data/lib/simple_form/inputs/base.rb +18 -0
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form/wrappers/root.rb +1 -0
- data/test/components/custom_components_test.rb +62 -0
- data/test/components/label_test.rb +28 -0
- data/test/form_builder/general_test.rb +34 -0
- data/test/form_builder/input_field_test.rb +25 -0
- data/test/form_builder/wrapper_test.rb +21 -2
- data/test/support/misc_helpers.rb +14 -0
- data/test/support/models.rb +9 -3
- metadata +4 -14
@@ -1,4 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Uncomment this and change the path if necessary to include your own
|
4
|
+
# components.
|
5
|
+
# See https://github.com/plataformatec/simple_form#custom-components to know
|
6
|
+
# more about custom components.
|
7
|
+
# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
|
8
|
+
#
|
2
9
|
# Use this setup block to configure all options available in SimpleForm.
|
3
10
|
SimpleForm.setup do |config|
|
4
11
|
# Don't forget to edit this file to adapt it to your needs (specially
|
@@ -8,7 +15,7 @@ SimpleForm.setup do |config|
|
|
8
15
|
# doesn't provide styles for hints. You will need to provide your own CSS styles for hints.
|
9
16
|
# Uncomment them to enable hints.
|
10
17
|
|
11
|
-
config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error do |b|
|
18
|
+
config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
12
19
|
b.use :html5
|
13
20
|
b.use :placeholder
|
14
21
|
b.optional :maxlength
|
@@ -22,7 +29,7 @@ SimpleForm.setup do |config|
|
|
22
29
|
# b.use :hint, wrap_with: { tag: :span, class: :hint }
|
23
30
|
end
|
24
31
|
|
25
|
-
config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error do |b|
|
32
|
+
config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
26
33
|
b.use :html5
|
27
34
|
b.use :placeholder
|
28
35
|
b.optional :maxlength
|
@@ -32,7 +39,7 @@ SimpleForm.setup do |config|
|
|
32
39
|
b.optional :readonly
|
33
40
|
|
34
41
|
b.wrapper :label_wrapper, tag: :div, class: 'small-3 columns' do |ba|
|
35
|
-
ba.use :label, class: 'right inline'
|
42
|
+
ba.use :label, class: 'text-right inline'
|
36
43
|
end
|
37
44
|
|
38
45
|
b.wrapper :right_input_wrapper, tag: :div, class: 'small-9 columns' do |ba|
|
@@ -64,7 +71,7 @@ SimpleForm.setup do |config|
|
|
64
71
|
# Note that you need to adapt this wrapper to your needs. If you need a 4
|
65
72
|
# columns form then change the wrapper class to 'small-3', if you need
|
66
73
|
# only two use 'small-6' and so on.
|
67
|
-
config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error do |b|
|
74
|
+
config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
68
75
|
b.use :html5
|
69
76
|
b.use :placeholder
|
70
77
|
b.optional :maxlength
|
@@ -83,7 +90,7 @@ SimpleForm.setup do |config|
|
|
83
90
|
# Examples of use:
|
84
91
|
# - wrapper_html: {class: 'row'}, custom_wrapper_html: {class: 'column small-12'}
|
85
92
|
# - custom_wrapper_html: {class: 'column small-3 end'}
|
86
|
-
config.wrappers :customizable_wrapper, tag: 'div', error_class: :error do |b|
|
93
|
+
config.wrappers :customizable_wrapper, tag: 'div', error_class: :error, valid_class: :valid do |b|
|
87
94
|
b.use :html5
|
88
95
|
b.optional :readonly
|
89
96
|
|
@@ -108,4 +115,8 @@ SimpleForm.setup do |config|
|
|
108
115
|
|
109
116
|
# The default wrapper to be used by the FormBuilder.
|
110
117
|
config.default_wrapper = :vertical_form
|
118
|
+
|
119
|
+
# Defines validation classes to the input_field. By default it's nil.
|
120
|
+
# config.input_field_valid_class = 'is-valid'
|
121
|
+
# config.input_field_error_class = 'is-invalid'
|
111
122
|
end
|
data/lib/simple_form.rb
CHANGED
@@ -122,7 +122,7 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
|
|
122
122
|
|
123
123
|
# Collection of methods to detect if a file type was given.
|
124
124
|
mattr_accessor :file_methods
|
125
|
-
@@file_methods = %i[mounted_as file? public_filename]
|
125
|
+
@@file_methods = %i[mounted_as file? public_filename attached?]
|
126
126
|
|
127
127
|
# Custom mappings for input types. This should be a hash containing a regexp
|
128
128
|
# to match as key, and the input type that will be used when the field name
|
@@ -200,6 +200,12 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
|
|
200
200
|
mattr_accessor :i18n_scope
|
201
201
|
@@i18n_scope = 'simple_form'
|
202
202
|
|
203
|
+
mattr_accessor :input_field_error_class
|
204
|
+
@@input_field_error_class = nil
|
205
|
+
|
206
|
+
mattr_accessor :input_field_valid_class
|
207
|
+
@@input_field_valid_class = nil
|
208
|
+
|
203
209
|
# Retrieves a given wrapper
|
204
210
|
def self.wrapper(name)
|
205
211
|
@@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}"
|
@@ -229,7 +235,7 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
|
|
229
235
|
SimpleForm::Wrappers::Root.new(builder.to_a, options)
|
230
236
|
end
|
231
237
|
|
232
|
-
wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|
|
238
|
+
wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
|
233
239
|
b.use :html5
|
234
240
|
|
235
241
|
b.use :min_max
|
@@ -265,6 +271,49 @@ See https://github.com/plataformatec/simple_form/pull/997 for more information.
|
|
265
271
|
@@configured = true
|
266
272
|
yield self
|
267
273
|
end
|
274
|
+
|
275
|
+
# Includes a component to be used by Simple Form. Methods defined in a
|
276
|
+
# component will be exposed to be used in the wrapper as Simple::Components
|
277
|
+
#
|
278
|
+
# Examples
|
279
|
+
#
|
280
|
+
# # The application needs to tell where the components will be.
|
281
|
+
# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
|
282
|
+
#
|
283
|
+
# # Create a custom component in the path specified above.
|
284
|
+
# # lib/components/input_group_component.rb
|
285
|
+
# module InputGroupComponent
|
286
|
+
# def prepend
|
287
|
+
# ...
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# def append
|
291
|
+
# ...
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
#
|
295
|
+
# SimpleForm.setup do |config|
|
296
|
+
# # Create a wrapper using the custom component.
|
297
|
+
# config.wrappers :input_group, tag: :div, error_class: :error do |b|
|
298
|
+
# b.use :label
|
299
|
+
# b.optional :prepend
|
300
|
+
# b.use :input
|
301
|
+
# b.use :append
|
302
|
+
# end
|
303
|
+
# end
|
304
|
+
#
|
305
|
+
# # Using the custom component in the form.
|
306
|
+
# <%= simple_form_for @blog, wrapper: input_group do |f| %>
|
307
|
+
# <%= f.input :title, prepend: true %>
|
308
|
+
# <% end %>
|
309
|
+
#
|
310
|
+
def self.include_component(component)
|
311
|
+
if Module === component
|
312
|
+
SimpleForm::Inputs::Base.include(component)
|
313
|
+
else
|
314
|
+
raise TypeError, "SimpleForm.include_component expects a module but got: #{component.class}"
|
315
|
+
end
|
316
|
+
end
|
268
317
|
end
|
269
318
|
|
270
319
|
require 'simple_form/railtie' if defined?(Rails)
|
@@ -14,6 +14,14 @@ module SimpleForm
|
|
14
14
|
object && object.respond_to?(:errors) && errors.present?
|
15
15
|
end
|
16
16
|
|
17
|
+
def has_value?
|
18
|
+
object && object.respond_to?(attribute_name) && object.send(attribute_name).present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
!has_errors? && has_value?
|
23
|
+
end
|
24
|
+
|
17
25
|
protected
|
18
26
|
|
19
27
|
def error_text
|
@@ -7,18 +7,24 @@ module SimpleForm
|
|
7
7
|
module ClassMethods #:nodoc:
|
8
8
|
def translate_required_html
|
9
9
|
i18n_cache :translate_required_html do
|
10
|
-
I18n.t(:"
|
10
|
+
I18n.t(:"required.html", scope: i18n_scope, default:
|
11
11
|
%(<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr>)
|
12
12
|
)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def translate_required_text
|
17
|
-
I18n.t(:"
|
17
|
+
I18n.t(:"required.text", scope: i18n_scope, default: 'required')
|
18
18
|
end
|
19
19
|
|
20
20
|
def translate_required_mark
|
21
|
-
I18n.t(:"
|
21
|
+
I18n.t(:"required.mark", scope: i18n_scope, default: '*')
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def i18n_scope
|
27
|
+
SimpleForm.i18n_scope
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
@@ -28,19 +28,9 @@ module SimpleForm
|
|
28
28
|
length_validator.options[:tokenizer]
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def maximum_length_value_from(length_validator)
|
35
|
-
if length_validator && !has_tokenizer?(length_validator)
|
36
|
-
length_validator.options[:is] || length_validator.options[:maximum]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
elsif ActionPack::VERSION::STRING >= '5'
|
40
|
-
def maximum_length_value_from(length_validator)
|
41
|
-
if length_validator
|
42
|
-
length_validator.options[:is] || length_validator.options[:maximum]
|
43
|
-
end
|
31
|
+
def maximum_length_value_from(length_validator)
|
32
|
+
if length_validator
|
33
|
+
length_validator.options[:is] || length_validator.options[:maximum]
|
44
34
|
end
|
45
35
|
end
|
46
36
|
end
|
@@ -28,19 +28,9 @@ module SimpleForm
|
|
28
28
|
length_validator.options[:tokenizer]
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def minimum_length_value_from(length_validator)
|
35
|
-
if length_validator && !has_tokenizer?(length_validator)
|
36
|
-
length_validator.options[:is] || length_validator.options[:minimum]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
elsif ActionPack::VERSION::STRING >= '5'
|
40
|
-
def minimum_length_value_from(length_validator)
|
41
|
-
if length_validator
|
42
|
-
length_validator.options[:is] || length_validator.options[:minimum]
|
43
|
-
end
|
31
|
+
def minimum_length_value_from(length_validator)
|
32
|
+
if length_validator
|
33
|
+
length_validator.options[:is] || length_validator.options[:minimum]
|
44
34
|
end
|
45
35
|
end
|
46
36
|
end
|
@@ -18,20 +18,20 @@ module SimpleForm
|
|
18
18
|
extend MapType
|
19
19
|
include SimpleForm::Inputs
|
20
20
|
|
21
|
-
map_type :text,
|
22
|
-
map_type :file,
|
23
|
-
map_type :string, :email, :search, :tel, :url, :uuid, to: SimpleForm::Inputs::StringInput
|
24
|
-
map_type :password,
|
25
|
-
map_type :integer, :decimal, :float,
|
26
|
-
map_type :range,
|
27
|
-
map_type :check_boxes,
|
28
|
-
map_type :radio_buttons,
|
29
|
-
map_type :select,
|
30
|
-
map_type :grouped_select,
|
31
|
-
map_type :date, :time, :datetime,
|
32
|
-
map_type :country, :time_zone,
|
33
|
-
map_type :boolean,
|
34
|
-
map_type :hidden,
|
21
|
+
map_type :text, :hstore, :json, :jsonb, to: SimpleForm::Inputs::TextInput
|
22
|
+
map_type :file, to: SimpleForm::Inputs::FileInput
|
23
|
+
map_type :string, :email, :search, :tel, :url, :uuid, :citext, to: SimpleForm::Inputs::StringInput
|
24
|
+
map_type :password, to: SimpleForm::Inputs::PasswordInput
|
25
|
+
map_type :integer, :decimal, :float, to: SimpleForm::Inputs::NumericInput
|
26
|
+
map_type :range, to: SimpleForm::Inputs::RangeInput
|
27
|
+
map_type :check_boxes, to: SimpleForm::Inputs::CollectionCheckBoxesInput
|
28
|
+
map_type :radio_buttons, to: SimpleForm::Inputs::CollectionRadioButtonsInput
|
29
|
+
map_type :select, to: SimpleForm::Inputs::CollectionSelectInput
|
30
|
+
map_type :grouped_select, to: SimpleForm::Inputs::GroupedCollectionSelectInput
|
31
|
+
map_type :date, :time, :datetime, to: SimpleForm::Inputs::DateTimeInput
|
32
|
+
map_type :country, :time_zone, to: SimpleForm::Inputs::PriorityInput
|
33
|
+
map_type :boolean, to: SimpleForm::Inputs::BooleanInput
|
34
|
+
map_type :hidden, to: SimpleForm::Inputs::HiddenInput
|
35
35
|
|
36
36
|
def self.discovery_cache
|
37
37
|
@discovery_cache ||= {}
|
@@ -138,6 +138,29 @@ module SimpleForm
|
|
138
138
|
# <input class="string required" id="user_name" maxlength="100"
|
139
139
|
# name="user[name]" type="text" value="Carlos" />
|
140
140
|
#
|
141
|
+
# It also support validation classes once it is configured.
|
142
|
+
#
|
143
|
+
# # config/initializers/simple_form.rb
|
144
|
+
# SimpleForm.setup do |config|
|
145
|
+
# config.input_field_valid_class = 'is-valid'
|
146
|
+
# config.input_field_error_class = 'is-invalid'
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# simple_form_for @user do |f|
|
150
|
+
# f.input_field :name
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# When the validation happens, the input will be rendered with
|
154
|
+
# the class configured according to the validation:
|
155
|
+
#
|
156
|
+
# - when the input is valid:
|
157
|
+
#
|
158
|
+
# <input class="is-valid string required" id="user_name" value="Carlos" />
|
159
|
+
#
|
160
|
+
# - when the input is invalid:
|
161
|
+
#
|
162
|
+
# <input class="is-invalid string required" id="user_name" value="" />
|
163
|
+
#
|
141
164
|
def input_field(attribute_name, options = {})
|
142
165
|
components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS)
|
143
166
|
|
@@ -147,7 +170,7 @@ module SimpleForm
|
|
147
170
|
|
148
171
|
input = find_input(attribute_name, options)
|
149
172
|
wrapper = find_wrapper(input.input_type, options)
|
150
|
-
components = components.
|
173
|
+
components = build_input_field_components(components.push(:input))
|
151
174
|
|
152
175
|
SimpleForm::Wrappers::Root.new(components, wrapper.options.merge(wrapper: false)).render input
|
153
176
|
end
|
@@ -527,7 +550,7 @@ module SimpleForm
|
|
527
550
|
case input_type
|
528
551
|
when :timestamp
|
529
552
|
:datetime
|
530
|
-
when :string, nil
|
553
|
+
when :string, :citext, nil
|
531
554
|
case attribute_name.to_s
|
532
555
|
when /password/ then :password
|
533
556
|
when /time_zone/ then :time_zone
|
@@ -646,5 +669,31 @@ module SimpleForm
|
|
646
669
|
|
647
670
|
nil
|
648
671
|
end
|
672
|
+
|
673
|
+
def build_input_field_components(components)
|
674
|
+
components.map do |component|
|
675
|
+
if component == :input
|
676
|
+
SimpleForm::Wrappers::Leaf.new(component, build_input_field_options)
|
677
|
+
else
|
678
|
+
SimpleForm::Wrappers::Leaf.new(component)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
end
|
682
|
+
|
683
|
+
def build_input_field_options
|
684
|
+
input_field_options = {}
|
685
|
+
valid_class = SimpleForm.input_field_valid_class
|
686
|
+
error_class = SimpleForm.input_field_error_class
|
687
|
+
|
688
|
+
if error_class.present?
|
689
|
+
input_field_options[:error_class] = error_class
|
690
|
+
end
|
691
|
+
|
692
|
+
if valid_class.present?
|
693
|
+
input_field_options[:valid_class] = valid_class
|
694
|
+
end
|
695
|
+
|
696
|
+
input_field_options
|
697
|
+
end
|
649
698
|
end
|
650
699
|
end
|
@@ -191,6 +191,8 @@ module SimpleForm
|
|
191
191
|
|
192
192
|
def merge_wrapper_options(options, wrapper_options)
|
193
193
|
if wrapper_options
|
194
|
+
wrapper_options = set_input_classes(wrapper_options)
|
195
|
+
|
194
196
|
wrapper_options.merge(options) do |key, oldval, newval|
|
195
197
|
case key.to_s
|
196
198
|
when "class"
|
@@ -206,6 +208,22 @@ module SimpleForm
|
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
211
|
+
def set_input_classes(wrapper_options)
|
212
|
+
wrapper_options = wrapper_options.dup
|
213
|
+
error_class = wrapper_options.delete(:error_class)
|
214
|
+
valid_class = wrapper_options.delete(:valid_class)
|
215
|
+
|
216
|
+
if error_class.present? && has_errors?
|
217
|
+
wrapper_options[:class] = "#{wrapper_options[:class]} #{error_class}"
|
218
|
+
end
|
219
|
+
|
220
|
+
if valid_class.present? && valid?
|
221
|
+
wrapper_options[:class] = "#{wrapper_options[:class]} #{valid_class}"
|
222
|
+
end
|
223
|
+
|
224
|
+
wrapper_options
|
225
|
+
end
|
226
|
+
|
209
227
|
def i18n_scope
|
210
228
|
SimpleForm.i18n_scope
|
211
229
|
end
|
data/lib/simple_form/version.rb
CHANGED
@@ -30,6 +30,7 @@ module SimpleForm
|
|
30
30
|
end
|
31
31
|
css << (options[:wrapper_error_class] || @defaults[:error_class]) if input.has_errors?
|
32
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?
|
33
34
|
css.compact
|
34
35
|
end
|
35
36
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
# Module that represents a custom component.
|
6
|
+
module Numbers
|
7
|
+
def number(wrapper_options = nil)
|
8
|
+
@number ||= options[:number].to_s.html_safe
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Module that represents a custom component.
|
13
|
+
module InputGroup
|
14
|
+
def prepend(wrapper_options = nil)
|
15
|
+
span_tag = content_tag(:span, options[:prepend], class: 'input-group-text')
|
16
|
+
template.content_tag(:div, span_tag, class: 'input-group-prepend')
|
17
|
+
end
|
18
|
+
|
19
|
+
def append(wrapper_options = nil)
|
20
|
+
span_tag = content_tag(:span, options[:append], class: 'input-group-text')
|
21
|
+
template.content_tag(:div, span_tag, class: 'input-group-append')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CustomComponentsTest < ActionView::TestCase
|
26
|
+
test 'includes the custom components' do
|
27
|
+
SimpleForm.include_component Numbers
|
28
|
+
|
29
|
+
custom_wrapper = SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
|
30
|
+
b.use :number, wrap_with: { tag: 'div', class: 'number' }
|
31
|
+
end
|
32
|
+
|
33
|
+
with_form_for @user, :name, number: 1, wrapper: custom_wrapper
|
34
|
+
|
35
|
+
assert_select 'div.number', text: '1'
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'includes custom components and use it as optional in the wrapper' do
|
39
|
+
SimpleForm.include_component InputGroup
|
40
|
+
|
41
|
+
custom_wrapper = SimpleForm.build tag: :div, class: 'custom_wrapper' do |b|
|
42
|
+
b.use :label
|
43
|
+
b.optional :prepend
|
44
|
+
b.use :input
|
45
|
+
b.use :append
|
46
|
+
end
|
47
|
+
|
48
|
+
with_form_for @user, :name, prepend: true, wrapper: custom_wrapper
|
49
|
+
|
50
|
+
assert_select 'div.input-group-prepend > span.input-group-text'
|
51
|
+
assert_select 'div.input-group-append > span.input-group-text'
|
52
|
+
end
|
53
|
+
|
54
|
+
test 'raises a TypeError when the component is not a Module' do
|
55
|
+
component = 'MyComponent'
|
56
|
+
|
57
|
+
exception = assert_raises TypeError do
|
58
|
+
SimpleForm.include_component(component)
|
59
|
+
end
|
60
|
+
assert_equal exception.message, "SimpleForm.include_component expects a module but got: String"
|
61
|
+
end
|
62
|
+
end
|