simple_form 1.4.2 → 1.5.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.
- data/.gitignore +1 -0
- data/.travis.yml +9 -1
- data/CHANGELOG.rdoc +20 -0
- data/Gemfile +5 -4
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/lib/generators/simple_form/install_generator.rb +2 -6
- data/lib/generators/simple_form/templates/{simple_form.rb → config/initializers/simple_form.rb} +0 -0
- data/lib/generators/simple_form/templates/{en.yml → config/locales/simple_form.en.yml} +0 -0
- data/lib/simple_form.rb +1 -1
- data/lib/simple_form/action_view_extensions/builder.rb +12 -5
- data/lib/simple_form/action_view_extensions/form_helper.rb +13 -8
- data/lib/simple_form/components.rb +1 -1
- data/lib/simple_form/components/errors.rb +10 -2
- data/lib/simple_form/components/hints.rb +10 -0
- data/lib/simple_form/components/label_input.rb +5 -3
- data/lib/simple_form/components/labels.rb +10 -4
- data/lib/simple_form/components/placeholders.rb +10 -4
- data/lib/simple_form/error_notification.rb +1 -1
- data/lib/simple_form/form_builder.rb +10 -7
- data/lib/simple_form/helpers.rb +9 -0
- data/lib/simple_form/helpers/has_errors.rb +15 -0
- data/lib/simple_form/helpers/maxlength.rb +24 -0
- data/lib/simple_form/helpers/pattern.rb +28 -0
- data/lib/simple_form/helpers/required.rb +36 -0
- data/lib/simple_form/helpers/validators.rb +44 -0
- data/lib/simple_form/inputs.rb +5 -2
- data/lib/simple_form/inputs/base.rb +24 -47
- data/lib/simple_form/inputs/boolean_input.rb +1 -1
- data/lib/simple_form/inputs/collection_input.rb +1 -1
- data/lib/simple_form/inputs/date_time_input.rb +1 -1
- data/lib/simple_form/inputs/file_input.rb +9 -0
- data/lib/simple_form/inputs/hidden_input.rb +1 -1
- data/lib/simple_form/inputs/numeric_input.rb +20 -13
- data/lib/simple_form/inputs/password_input.rb +13 -0
- data/lib/simple_form/inputs/range_input.rb +16 -0
- data/lib/simple_form/inputs/string_input.rb +7 -24
- data/lib/simple_form/inputs/text_input.rb +12 -0
- data/lib/simple_form/version.rb +1 -1
- data/test/action_view_extensions/builder_test.rb +59 -0
- data/test/action_view_extensions/form_helper_test.rb +21 -0
- data/test/discovery_inputs.rb +2 -2
- data/test/form_builder_test.rb +54 -0
- data/test/inputs_test.rb +185 -20
- data/test/support/models.rb +23 -2
- data/test/test_helper.rb +1 -0
- metadata +17 -11
- data/Gemfile.lock +0 -54
- data/init.rb +0 -1
- data/lib/simple_form/has_errors.rb +0 -14
- data/lib/simple_form/inputs/mapping_input.rb +0 -29
@@ -0,0 +1,36 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Helpers
|
3
|
+
module Required
|
4
|
+
private
|
5
|
+
|
6
|
+
def attribute_required?
|
7
|
+
@required
|
8
|
+
end
|
9
|
+
|
10
|
+
def calculate_required
|
11
|
+
if !options[:required].nil?
|
12
|
+
options[:required]
|
13
|
+
elsif has_validators?
|
14
|
+
(attribute_validators + reflection_validators).any? do |v|
|
15
|
+
v.kind == :presence && valid_validator?(v)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
attribute_required_by_default?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Whether this input is valid for HTML 5 required attribute.
|
23
|
+
def has_required?
|
24
|
+
attribute_required? && SimpleForm.html5 && SimpleForm.browser_validations
|
25
|
+
end
|
26
|
+
|
27
|
+
def attribute_required_by_default?
|
28
|
+
SimpleForm.required_by_default
|
29
|
+
end
|
30
|
+
|
31
|
+
def required_class
|
32
|
+
attribute_required? ? :required : :optional
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Helpers
|
3
|
+
module Validators
|
4
|
+
private
|
5
|
+
|
6
|
+
def has_validators?
|
7
|
+
attribute_name && object.class.respond_to?(:validators_on)
|
8
|
+
end
|
9
|
+
|
10
|
+
def attribute_validators
|
11
|
+
object.class.validators_on(attribute_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def reflection_validators
|
15
|
+
reflection ? object.class.validators_on(reflection.name) : []
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_validator?(validator)
|
19
|
+
!conditional_validators?(validator) && action_validator_match?(validator)
|
20
|
+
end
|
21
|
+
|
22
|
+
def conditional_validators?(validator)
|
23
|
+
validator.options.include?(:if) || validator.options.include?(:unless)
|
24
|
+
end
|
25
|
+
|
26
|
+
def action_validator_match?(validator)
|
27
|
+
return true if !validator.options.include?(:on)
|
28
|
+
|
29
|
+
case validator.options[:on]
|
30
|
+
when :save
|
31
|
+
true
|
32
|
+
when :create
|
33
|
+
!object.persisted?
|
34
|
+
when :update
|
35
|
+
object.persisted?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_validator(validator)
|
40
|
+
attribute_validators.find { |v| validator === v }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/simple_form/inputs.rb
CHANGED
@@ -5,10 +5,13 @@ module SimpleForm
|
|
5
5
|
autoload :BooleanInput, 'simple_form/inputs/boolean_input'
|
6
6
|
autoload :CollectionInput, 'simple_form/inputs/collection_input'
|
7
7
|
autoload :DateTimeInput, 'simple_form/inputs/date_time_input'
|
8
|
+
autoload :FileInput, 'simple_form/inputs/file_input'
|
8
9
|
autoload :HiddenInput, 'simple_form/inputs/hidden_input'
|
9
|
-
autoload :MappingInput, 'simple_form/inputs/mapping_input'
|
10
10
|
autoload :NumericInput, 'simple_form/inputs/numeric_input'
|
11
|
+
autoload :PasswordInput, 'simple_form/inputs/password_input'
|
11
12
|
autoload :PriorityInput, 'simple_form/inputs/priority_input'
|
13
|
+
autoload :RangeInput, 'simple_form/inputs/range_input'
|
12
14
|
autoload :StringInput, 'simple_form/inputs/string_input'
|
15
|
+
autoload :TextInput, 'simple_form/inputs/text_input'
|
13
16
|
end
|
14
|
-
end
|
17
|
+
end
|
@@ -9,12 +9,26 @@ module SimpleForm
|
|
9
9
|
:update => :edit
|
10
10
|
}
|
11
11
|
|
12
|
+
include SimpleForm::Helpers::Required
|
13
|
+
include SimpleForm::Helpers::Validators
|
14
|
+
include SimpleForm::Helpers::Maxlength
|
15
|
+
include SimpleForm::Helpers::Pattern
|
16
|
+
|
12
17
|
include SimpleForm::Components::Errors
|
13
18
|
include SimpleForm::Components::Hints
|
14
19
|
include SimpleForm::Components::LabelInput
|
15
20
|
include SimpleForm::Components::Placeholders
|
16
21
|
include SimpleForm::Components::Wrapper
|
17
22
|
|
23
|
+
# Enables certain components support to the given input.
|
24
|
+
def self.enable(*args)
|
25
|
+
args.each { |m| alias_method m, :"enabled_#{m}" }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.disable(*args)
|
29
|
+
args.each { |m| alias_method m, :"disabled_#{m}" }
|
30
|
+
end
|
31
|
+
|
18
32
|
attr_reader :attribute_name, :column, :input_type, :reflection,
|
19
33
|
:options, :input_html_options
|
20
34
|
|
@@ -27,8 +41,9 @@ module SimpleForm
|
|
27
41
|
@input_type = input_type
|
28
42
|
@reflection = options.delete(:reflection)
|
29
43
|
@options = options
|
44
|
+
@required = calculate_required
|
30
45
|
@input_html_options = html_options_for(:input, input_html_classes).tap do |o|
|
31
|
-
o[:required] = true if has_required?
|
46
|
+
o[:required] = true if has_required?
|
32
47
|
o[:disabled] = true if disabled?
|
33
48
|
o[:autofocus] = true if has_autofocus? && SimpleForm.html5
|
34
49
|
end
|
@@ -56,57 +71,24 @@ module SimpleForm
|
|
56
71
|
wrap(content)
|
57
72
|
end
|
58
73
|
|
59
|
-
|
74
|
+
private
|
60
75
|
|
61
|
-
def
|
62
|
-
|
76
|
+
def add_size!
|
77
|
+
input_html_options[:size] ||= [limit, SimpleForm.default_input_size].compact.min
|
63
78
|
end
|
64
79
|
|
65
|
-
def
|
66
|
-
|
67
|
-
options[:required]
|
68
|
-
elsif has_validators?
|
69
|
-
(attribute_validators + reflection_validators).any? do |v|
|
70
|
-
v.kind == :presence && !conditional_validators?(v)
|
71
|
-
end
|
72
|
-
else
|
73
|
-
attribute_required_by_default?
|
74
|
-
end
|
80
|
+
def limit
|
81
|
+
column && column.limit
|
75
82
|
end
|
76
83
|
|
77
|
-
|
78
|
-
|
79
|
-
attribute_required? && SimpleForm.html5 && SimpleForm.browser_validations
|
84
|
+
def components_list
|
85
|
+
options[:components] || SimpleForm.components
|
80
86
|
end
|
81
87
|
|
82
88
|
def has_autofocus?
|
83
89
|
options[:autofocus]
|
84
90
|
end
|
85
91
|
|
86
|
-
def has_validators?
|
87
|
-
attribute_name && object.class.respond_to?(:validators_on)
|
88
|
-
end
|
89
|
-
|
90
|
-
def attribute_validators
|
91
|
-
object.class.validators_on(attribute_name)
|
92
|
-
end
|
93
|
-
|
94
|
-
def reflection_validators
|
95
|
-
reflection ? object.class.validators_on(reflection.name) : []
|
96
|
-
end
|
97
|
-
|
98
|
-
def conditional_validators?(validator)
|
99
|
-
validator.options.include?(:if) || validator.options.include?(:unless)
|
100
|
-
end
|
101
|
-
|
102
|
-
def attribute_required_by_default?
|
103
|
-
SimpleForm.required_by_default
|
104
|
-
end
|
105
|
-
|
106
|
-
def required_class
|
107
|
-
attribute_required? ? :required : :optional
|
108
|
-
end
|
109
|
-
|
110
92
|
# Find reflection name when available, otherwise use attribute
|
111
93
|
def reflection_or_attribute_name
|
112
94
|
reflection ? reflection.name : attribute_name
|
@@ -120,7 +102,7 @@ module SimpleForm
|
|
120
102
|
end
|
121
103
|
|
122
104
|
def disabled?
|
123
|
-
options[:disabled]
|
105
|
+
options[:disabled] == true
|
124
106
|
end
|
125
107
|
|
126
108
|
# Lookup translations for the given namespace using I18n, based on object name,
|
@@ -197,11 +179,6 @@ module SimpleForm
|
|
197
179
|
action = action.to_sym
|
198
180
|
ACTIONS[action] || action
|
199
181
|
end
|
200
|
-
|
201
|
-
def input_method
|
202
|
-
self.class.mappings[input_type] or
|
203
|
-
raise("Could not find method for #{input_type.inspect}")
|
204
|
-
end
|
205
182
|
end
|
206
183
|
end
|
207
184
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
module SimpleForm
|
2
2
|
module Inputs
|
3
3
|
class NumericInput < Base
|
4
|
+
enable :placeholder
|
5
|
+
|
4
6
|
def input
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
add_size!
|
8
|
+
if SimpleForm.html5
|
9
|
+
input_html_options[:type] ||= "number"
|
10
|
+
input_html_options[:step] ||= integer? ? 1 : "any"
|
11
|
+
infer_attributes_from_validations!
|
12
|
+
end
|
9
13
|
@builder.text_field(attribute_name, input_html_options)
|
10
14
|
end
|
11
15
|
|
@@ -13,10 +17,11 @@ module SimpleForm
|
|
13
17
|
super.unshift("numeric")
|
14
18
|
end
|
15
19
|
|
16
|
-
|
20
|
+
private
|
17
21
|
|
18
|
-
|
19
|
-
|
22
|
+
# Rails adds the size attr by default, if the :size key does not exist.
|
23
|
+
def add_size!
|
24
|
+
input_html_options[:size] ||= nil
|
20
25
|
end
|
21
26
|
|
22
27
|
def infer_attributes_from_validations!
|
@@ -50,15 +55,17 @@ module SimpleForm
|
|
50
55
|
end
|
51
56
|
|
52
57
|
def find_numericality_validator
|
53
|
-
|
58
|
+
find_validator(ActiveModel::Validations::NumericalityValidator)
|
54
59
|
end
|
55
60
|
|
56
|
-
private
|
57
|
-
|
58
61
|
def evaluate_validator_option(option)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
if option.is_a?(Numeric)
|
63
|
+
option
|
64
|
+
elsif option.is_a?(Symbol)
|
65
|
+
object.send(option)
|
66
|
+
elsif option.respond_to?(:call)
|
67
|
+
option.call(object)
|
68
|
+
end
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
@@ -1,42 +1,25 @@
|
|
1
1
|
module SimpleForm
|
2
2
|
module Inputs
|
3
3
|
class StringInput < Base
|
4
|
-
|
5
|
-
|
6
|
-
map_type :string, :email, :search, :tel, :url, :to => :text_field
|
7
|
-
map_type :password, :to => :password_field
|
4
|
+
enable :placeholder
|
8
5
|
|
9
6
|
def input
|
10
|
-
input_html_options[:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@builder.send(input_method, attribute_name, input_html_options)
|
7
|
+
input_html_options[:type] ||= input_type if SimpleForm.html5 && !string?
|
8
|
+
add_maxlength!
|
9
|
+
add_pattern!
|
10
|
+
add_size!
|
11
|
+
@builder.text_field(attribute_name, input_html_options)
|
17
12
|
end
|
18
13
|
|
19
14
|
def input_html_classes
|
20
15
|
string? ? super : super.unshift("string")
|
21
16
|
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
def limit
|
26
|
-
column && column.limit
|
27
|
-
end
|
28
|
-
|
29
|
-
def has_placeholder?
|
30
|
-
placeholder_present?
|
31
|
-
end
|
18
|
+
private
|
32
19
|
|
33
20
|
def string?
|
34
21
|
input_type == :string
|
35
22
|
end
|
36
|
-
|
37
|
-
def password?
|
38
|
-
input_type == :password
|
39
|
-
end
|
40
23
|
end
|
41
24
|
end
|
42
25
|
end
|
data/lib/simple_form/version.rb
CHANGED
@@ -96,6 +96,24 @@ class BuilderTest < ActionView::TestCase
|
|
96
96
|
assert_select 'form ul input[type=radio][value=false]#user_active_false'
|
97
97
|
end
|
98
98
|
|
99
|
+
test 'collection radio does not wrap the collection in the explicitly false collection wrapper tag' do
|
100
|
+
swap SimpleForm, :collection_wrapper_tag => :ul do
|
101
|
+
with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false
|
102
|
+
|
103
|
+
assert_no_select 'form ul'
|
104
|
+
assert_no_select 'form ul'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
test 'collection radio does not wrap the collection in the explicitly nil collection wrapper tag' do
|
109
|
+
swap SimpleForm, :collection_wrapper_tag => :ul do
|
110
|
+
with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => nil
|
111
|
+
|
112
|
+
assert_no_select 'form ul'
|
113
|
+
assert_no_select 'form ul'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
99
117
|
test 'collection radio does not wrap the collection by default' do
|
100
118
|
with_collection_radio @user, :active, [true, false], :to_s, :to_s
|
101
119
|
|
@@ -118,6 +136,20 @@ class BuilderTest < ActionView::TestCase
|
|
118
136
|
assert_select 'form li input[type=radio][value=false]#user_active_false'
|
119
137
|
end
|
120
138
|
|
139
|
+
test 'collection radio does not wrap each label/radio in the explicitly false item wrapper tag' do
|
140
|
+
with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false
|
141
|
+
|
142
|
+
assert_no_select 'form span input[type=radio][value=true]#user_active_true'
|
143
|
+
assert_no_select 'form span input[type=radio][value=false]#user_active_false'
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'collection radio does not wrap each label/radio in the explicitly nil item wrapper tag' do
|
147
|
+
with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => nil
|
148
|
+
|
149
|
+
assert_no_select 'form span input[type=radio][value=true]#user_active_true'
|
150
|
+
assert_no_select 'form span input[type=radio][value=false]#user_active_false'
|
151
|
+
end
|
152
|
+
|
121
153
|
test 'collection radio wrap items in a span tag by default' do
|
122
154
|
with_collection_radio @user, :active, [true, false], :to_s, :to_s
|
123
155
|
|
@@ -246,6 +278,13 @@ class BuilderTest < ActionView::TestCase
|
|
246
278
|
assert_select 'form ul input[type=checkbox][value=false]#user_active_false'
|
247
279
|
end
|
248
280
|
|
281
|
+
test 'collection check box does not wrap the collection in the explicitly false collection wrapper tag' do
|
282
|
+
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false, :item_wrapper_tag => false
|
283
|
+
|
284
|
+
assert_select 'form > input[type=checkbox][value=true]#user_active_true'
|
285
|
+
assert_select 'form > input[type=checkbox][value=false]#user_active_false'
|
286
|
+
end
|
287
|
+
|
249
288
|
test 'collection check box does not wrap the collection by default' do
|
250
289
|
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s
|
251
290
|
|
@@ -268,6 +307,13 @@ class BuilderTest < ActionView::TestCase
|
|
268
307
|
assert_select 'form li input[type=checkbox][value=false]#user_active_false'
|
269
308
|
end
|
270
309
|
|
310
|
+
test 'collection check box does not wrapp each label/radio in the explicitly false item wrapper tag' do
|
311
|
+
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false
|
312
|
+
|
313
|
+
assert_select 'form > input[type=checkbox][value=true]#user_active_true'
|
314
|
+
assert_select 'form > input[type=checkbox][value=false]#user_active_false'
|
315
|
+
end
|
316
|
+
|
271
317
|
test 'collection check box wrap items in a span tag by default' do
|
272
318
|
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s
|
273
319
|
|
@@ -290,6 +336,19 @@ class BuilderTest < ActionView::TestCase
|
|
290
336
|
end
|
291
337
|
end
|
292
338
|
|
339
|
+
test 'fields for with a hash like model yeilds an instance of FormBuilder' do
|
340
|
+
@hash_backed_author = HashBackedAuthor.new
|
341
|
+
|
342
|
+
with_concat_form_for(:user) do |f|
|
343
|
+
f.simple_fields_for(:author, @hash_backed_author) do |author|
|
344
|
+
assert author.instance_of?(SimpleForm::FormBuilder)
|
345
|
+
author.input :name
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
assert_select "input[name='user[author][name]'][value='hash backed author']"
|
350
|
+
end
|
351
|
+
|
293
352
|
test 'fields for yields an instance of CustomBuilder if main builder is a CustomBuilder' do
|
294
353
|
with_custom_form_for(:user) do |f|
|
295
354
|
f.simple_fields_for(:company) do |company|
|