simple_form 2.0.4 → 2.1.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.

Files changed (36) hide show
  1. data/CHANGELOG.md +33 -301
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +30 -12
  4. data/lib/generators/simple_form/install_generator.rb +7 -4
  5. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +26 -0
  6. data/lib/simple_form.rb +11 -8
  7. data/lib/simple_form/action_view_extensions/builder.rb +32 -18
  8. data/lib/simple_form/action_view_extensions/builder.rb.orig +247 -0
  9. data/lib/simple_form/components.rb +12 -10
  10. data/lib/simple_form/components/hints.rb +1 -1
  11. data/lib/simple_form/components/label_input.rb +1 -1
  12. data/lib/simple_form/components/maxlength.rb +1 -1
  13. data/lib/simple_form/components/min_max.rb +1 -1
  14. data/lib/simple_form/components/pattern.rb +1 -1
  15. data/lib/simple_form/form_builder.rb +6 -3
  16. data/lib/simple_form/form_builder.rb.orig +486 -0
  17. data/lib/simple_form/helpers/validators.rb +2 -2
  18. data/lib/simple_form/inputs.rb +19 -17
  19. data/lib/simple_form/inputs/base.rb +8 -2
  20. data/lib/simple_form/inputs/date_time_input.rb +0 -4
  21. data/lib/simple_form/version.rb +1 -1
  22. data/lib/simple_form/version.rb.orig +7 -0
  23. data/lib/simple_form/wrappers/root.rb +3 -1
  24. data/test/action_view_extensions/builder_test.rb +113 -67
  25. data/test/action_view_extensions/form_helper_test.rb +5 -0
  26. data/test/components/label_test.rb +27 -17
  27. data/test/form_builder/association_test.rb +10 -7
  28. data/test/form_builder/general_test.rb +48 -25
  29. data/test/form_builder/input_field_test.rb +45 -0
  30. data/test/form_builder/wrapper_test.rb +22 -0
  31. data/test/generators/simple_form_generator_test.rb +8 -0
  32. data/test/inputs/datetime_input_test.rb +2 -2
  33. data/test/inputs/grouped_collection_select_input_test.rb +15 -0
  34. data/test/support/misc_helpers.rb +6 -0
  35. data/test/test_helper.rb +6 -1
  36. metadata +12 -2
@@ -69,6 +69,11 @@ class FormHelperTest < ActionView::TestCase
69
69
  assert_select 'form.simple_form.edit_superuser'
70
70
  end
71
71
 
72
+ test 'SimpleForm should add last object name as css class to form when there is array of objects' do
73
+ with_concat_form_for([Company.new, @user])
74
+ assert_select 'form.simple_form.edit_user'
75
+ end
76
+
72
77
  test 'SimpleForm should not add object class to form if css_class is specified' do
73
78
  with_concat_form_for(:user, :html => {:class => nil})
74
79
  assert_no_select 'form.user'
@@ -38,7 +38,7 @@ class IsolatedLabelTest < ActionView::TestCase
38
38
  @controller.action_name = "new"
39
39
  store_translations(:en, :simple_form => { :labels => { :user => {
40
40
  :new => { :description => 'Nova descrição' }
41
- } } } ) do
41
+ } } }) do
42
42
  with_label_for @user, :description, :text
43
43
  assert_select 'label[for=user_description]', /Nova descrição/
44
44
  end
@@ -48,7 +48,7 @@ class IsolatedLabelTest < ActionView::TestCase
48
48
  @controller.action_name = "create"
49
49
  store_translations(:en, :simple_form => { :labels => { :user => {
50
50
  :new => { :description => 'Nova descrição' }
51
- } } } ) do
51
+ } } }) do
52
52
  with_label_for @user, :description, :text
53
53
  assert_select 'label[for=user_description]', /Nova descrição/
54
54
  end
@@ -66,43 +66,53 @@ class IsolatedLabelTest < ActionView::TestCase
66
66
  test 'label should use i18n based on model and attribute to lookup translation' do
67
67
  store_translations(:en, :simple_form => { :labels => { :user => {
68
68
  :description => 'Descrição'
69
- } } } ) do
69
+ } } }) do
70
70
  with_label_for @user, :description, :text
71
71
  assert_select 'label[for=user_description]', /Descrição/
72
72
  end
73
73
  end
74
74
 
75
- test 'input should use i18n under defaults to lookup translation' do
76
- store_translations(:en, :simple_form => { :labels => { :defaults => {:age => 'Idade'} } } ) do
75
+ test 'label should use i18n under defaults to lookup translation' do
76
+ store_translations(:en, :simple_form => { :labels => { :defaults => { :age => 'Idade' } } }) do
77
77
  with_label_for @user, :age, :integer
78
78
  assert_select 'label[for=user_age]', /Idade/
79
79
  end
80
80
  end
81
81
 
82
- test 'input should not use i18n label if translate is false' do
82
+ test 'label should not use i18n label if translate is false' do
83
83
  swap SimpleForm, :translate_labels => false do
84
- store_translations(:en, :simple_form => { :labels => { :defaults => {:age => 'Idade'} } } ) do
84
+ store_translations(:en, :simple_form => { :labels => { :defaults => { :age => 'Idade' } } }) do
85
85
  with_label_for @user, :age, :integer
86
86
  assert_select 'label[for=user_age]', /Age/
87
87
  end
88
88
  end
89
89
  end
90
90
 
91
- test 'label should use i18n with lookup for association name' do
91
+ test 'label uses i18n with lookup for association name' do
92
92
  store_translations(:en, :simple_form => { :labels => {
93
93
  :user => { :company => 'My company!' }
94
- } } ) do
94
+ } }) do
95
95
  with_label_for @user, :company_id, :string, :setup_association => true
96
96
  assert_select 'label[for=user_company_id]', /My company!/
97
97
  end
98
98
  end
99
99
 
100
+ test 'label uses i18n under defaults namespace to lookup for association name' do
101
+ store_translations(:en, :simple_form => { :labels => {
102
+ :defaults => { :company => 'Plataformatec' }
103
+ } }) do
104
+ with_label_for @user, :company, :string, :setup_association => true
105
+
106
+ assert_select 'form label', /Plataformatec/
107
+ end
108
+ end
109
+
100
110
  test 'label should do correct i18n lookup for nested models with nested translation' do
101
111
  @user.company = Company.new(1, 'Empresa')
102
112
 
103
113
  store_translations(:en, :simple_form => { :labels => {
104
114
  :user => { :name => 'Usuario', :company => { :name => 'Nome da empresa' } }
105
- } } ) do
115
+ } }) do
106
116
  with_concat_form_for @user do |f|
107
117
  concat f.input :name
108
118
  concat(f.simple_fields_for(:company) do |company_form|
@@ -121,7 +131,7 @@ class IsolatedLabelTest < ActionView::TestCase
121
131
  store_translations(:en, :simple_form => { :labels => {
122
132
  :user => { :name => 'Usuario' },
123
133
  :company => { :name => 'Nome da empresa' }
124
- } } ) do
134
+ } }) do
125
135
  with_concat_form_for @user do |f|
126
136
  concat f.input :name
127
137
  concat(f.simple_fields_for(:company) do |company_form|
@@ -140,7 +150,7 @@ class IsolatedLabelTest < ActionView::TestCase
140
150
  store_translations(:en, :simple_form => { :labels => {
141
151
  :user => { :name => 'Usuario' },
142
152
  :tags => { :name => 'Nome da empresa' }
143
- } } ) do
153
+ } }) do
144
154
  with_concat_form_for @user do |f|
145
155
  concat f.input :name
146
156
  concat(f.simple_fields_for(:tags, :child_index => "new_index") do |tags_form|
@@ -232,21 +242,21 @@ class IsolatedLabelTest < ActionView::TestCase
232
242
  end
233
243
 
234
244
  test 'label should use i18n to find required text' do
235
- store_translations(:en, :simple_form => { :required => { :text => 'campo requerido' }}) do
245
+ store_translations(:en, :simple_form => { :required => { :text => 'campo requerido' } }) do
236
246
  with_label_for @user, :name, :string
237
247
  assert_select 'form label abbr[title=campo requerido]', '*'
238
248
  end
239
249
  end
240
250
 
241
251
  test 'label should use i18n to find required mark' do
242
- store_translations(:en, :simple_form => { :required => { :mark => '*-*' }}) do
252
+ store_translations(:en, :simple_form => { :required => { :mark => '*-*' } }) do
243
253
  with_label_for @user, :name, :string
244
254
  assert_select 'form label abbr', '*-*'
245
255
  end
246
256
  end
247
257
 
248
258
  test 'label should use i18n to find required string tag' do
249
- store_translations(:en, :simple_form => { :required => { :html => '<span class="required" title="requerido">*</span>' }}) do
259
+ store_translations(:en, :simple_form => { :required => { :html => '<span class="required" title="requerido">*</span>' } }) do
250
260
  with_label_for @user, :name, :string
251
261
  assert_no_select 'form label abbr'
252
262
  assert_select 'form label span.required[title=requerido]', '*'
@@ -264,7 +274,7 @@ class IsolatedLabelTest < ActionView::TestCase
264
274
  end
265
275
 
266
276
  test 'label should allow overwriting of for attribute with input_html not containing id' do
267
- with_label_for @user, :name, :string, :label_html => { :for => 'my_new_id' }, :input_html => {:class => 'foo'}
277
+ with_label_for @user, :name, :string, :label_html => { :for => 'my_new_id' }, :input_html => { :class => 'foo' }
268
278
  assert_select 'label[for=my_new_id]'
269
279
  end
270
280
 
@@ -286,7 +296,7 @@ class IsolatedLabelTest < ActionView::TestCase
286
296
  test 'label should use i18n properly when object is not present' do
287
297
  store_translations(:en, :simple_form => { :labels => {
288
298
  :project => { :name => 'Nome' }
289
- } } ) do
299
+ } }) do
290
300
  with_label_for :project, :name, :string
291
301
  assert_select 'label[for=project_name]', /Nome/
292
302
  end
@@ -43,6 +43,7 @@ class AssociationTest < ActionView::TestCase
43
43
  test 'builder preloads collection association' do
44
44
  value = @user.tags = Object.new
45
45
  value.expects(:to_a).returns(value)
46
+
46
47
  with_association_for @user, :tags
47
48
  assert_select 'form select.select#user_tag_ids'
48
49
  assert_select 'form select option[value=1]', 'Tag 1'
@@ -51,19 +52,21 @@ class AssociationTest < ActionView::TestCase
51
52
  end
52
53
 
53
54
  test 'builder does not preload collection association if preload is false' do
54
- value = @user.company = Object.new
55
+ value = @user.tags = Object.new
55
56
  value.expects(:to_a).never
56
- with_association_for @user, :company, :preload => false
57
- assert_select 'form select.select#user_company_id'
58
- assert_select 'form select option[value=1]', 'Company 1'
59
- assert_select 'form select option[value=2]', 'Company 2'
60
- assert_select 'form select option[value=3]', 'Company 3'
57
+
58
+ with_association_for @user, :tags, :preload => false
59
+ assert_select 'form select.select#user_tag_ids'
60
+ assert_select 'form select option[value=1]', 'Tag 1'
61
+ assert_select 'form select option[value=2]', 'Tag 2'
62
+ assert_select 'form select option[value=3]', 'Tag 3'
61
63
  end
62
64
 
63
65
  test 'builder does not preload non-collection association' do
64
66
  value = @user.company = Object.new
65
67
  value.expects(:to_a).never
66
- with_association_for @user, :company, :preload => false
68
+
69
+ with_association_for @user, :company
67
70
  assert_select 'form select.select#user_company_id'
68
71
  assert_select 'form select option[value=1]', 'Company 1'
69
72
  assert_select 'form select option[value=2]', 'Company 2'
@@ -237,6 +237,11 @@ class FormBuilderTest < ActionView::TestCase
237
237
  assert_no_select 'form label'
238
238
  end
239
239
 
240
+ test 'builder should be able to disable the label for an input and return a html safe string' do
241
+ with_form_for @user, :name, :label => false, :wrapper => custom_wrapper_with_wrapped_label_input
242
+ assert_select 'form input#user_name'
243
+ end
244
+
240
245
  test 'builder should use custom label' do
241
246
  with_form_for @user, :name, :label => 'Yay!'
242
247
  assert_select 'form label', /Yay!/
@@ -259,6 +264,8 @@ class FormBuilderTest < ActionView::TestCase
259
264
 
260
265
  test 'builder should be able to disable a hint even if it exists in i18n' do
261
266
  store_translations(:en, :simple_form => { :hints => { :name => 'Hint test' } }) do
267
+ SimpleForm::Inputs::Base.any_instance.expects(:hint).never
268
+
262
269
  with_form_for @user, :name, :hint => false
263
270
  assert_no_select 'span.hint'
264
271
  end
@@ -299,49 +306,65 @@ class FormBuilderTest < ActionView::TestCase
299
306
  end
300
307
 
301
308
  # DEFAULT OPTIONS
302
- test 'builder should receive a default argument and pass it to the inputs' do
303
- with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
304
- f.input :name
309
+ [:input, :input_field].each do |method|
310
+ test "builder should receive a default argument and pass it to the inputs when calling '#{method}'" do
311
+ with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
312
+ f.send(method, :name)
313
+ end
314
+ assert_select 'input.default_class'
315
+ end
316
+
317
+ test "builder should receive a default argument and pass it to the inputs without changing the defaults when calling '#{method}'" do
318
+ with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f|
319
+ concat(f.send(method, :name))
320
+ concat(f.send(method, :credit_limit))
321
+ end
322
+
323
+ assert_select "input.string.default_class[name='user[name]']"
324
+ assert_no_select "input.string[name='user[credit_limit]']"
325
+ end
326
+
327
+ test "builder should receive a default argument and pass it to the inputs and nested form when calling '#{method}'" do
328
+ @user.company = Company.new(1, 'Empresa')
329
+
330
+ with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
331
+ concat(f.send(method, :name))
332
+ concat(f.simple_fields_for(:company) do |company_form|
333
+ concat(company_form.send(method, :name))
334
+ end)
335
+ end
336
+
337
+ assert_select "input.string.default_class[name='user[name]']"
338
+ assert_select "input.string.default_class[name='user[company_attributes][name]']"
305
339
  end
306
- assert_select 'input.default_class'
307
340
  end
308
341
 
309
- test 'builder should receive a default argument and pass it to the inputs, respecting the specific options' do
342
+ test "builder should receive a default argument and pass it to the inputs when calling 'input', respecting the specific options" do
310
343
  with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
311
344
  f.input :name, :input_html => { :id => 'specific_id' }
312
345
  end
313
346
  assert_select 'input.default_class#specific_id'
314
347
  end
315
348
 
316
- test 'builder should receive a default argument and pass it to the inputs, overwriting the defaults with specific options' do
317
- with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f|
318
- f.input :name, :input_html => { :id => 'specific_id' }
349
+ test "builder should receive a default argument and pass it to the inputs when calling 'input_field', respecting the specific options" do
350
+ with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
351
+ f.input_field :name, :id => 'specific_id'
319
352
  end
320
353
  assert_select 'input.default_class#specific_id'
321
354
  end
322
355
 
323
- test 'builder should receive a default argument and pass it to the inputs without changing the defaults' do
356
+ test "builder should receive a default argument and pass it to the inputs when calling 'input', overwriting the defaults with specific options" do
324
357
  with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f|
325
- concat(f.input :name)
326
- concat(f.input :credit_limit)
358
+ f.input :name, :input_html => { :id => 'specific_id' }
327
359
  end
328
-
329
- assert_select "input.string.default_class[name='user[name]']"
330
- assert_no_select "input.string[name='user[credit_limit]']"
360
+ assert_select 'input.default_class#specific_id'
331
361
  end
332
362
 
333
- test 'builder should receive a default argument and pass it to the inputs and nested form' do
334
- @user.company = Company.new(1, 'Empresa')
335
-
336
- with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f|
337
- concat(f.input :name)
338
- concat(f.simple_fields_for(:company) do |company_form|
339
- concat(company_form.input :name)
340
- end)
363
+ test "builder should receive a default argument and pass it to the inputs when calling 'input_field', overwriting the defaults with specific options" do
364
+ with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f|
365
+ f.input_field :name, :id => 'specific_id'
341
366
  end
342
-
343
- assert_select "input.string.default_class[name='user[name]']"
344
- assert_select "input.string.default_class[name='user[company_attributes][name]']"
367
+ assert_select 'input.default_class#specific_id'
345
368
  end
346
369
 
347
370
  # WITHOUT OBJECT
@@ -50,6 +50,51 @@ class InputFieldTest < ActionView::TestCase
50
50
  assert_no_select 'input.integer[as]'
51
51
  end
52
52
 
53
+ test 'builder input_field should use i18n to translate placeholder text' do
54
+ store_translations(:en, :simple_form => { :placeholders => { :user => {
55
+ :name => 'Name goes here'
56
+ } } }) do
57
+
58
+ with_concat_form_for(@user) do |f|
59
+ f.input_field :name
60
+ end
61
+
62
+ assert_select 'input.string[placeholder=Name goes here]'
63
+ end
64
+ end
65
+
66
+ test 'builder input_field should use min_max component' do
67
+ with_concat_form_for(@other_validating_user) do |f|
68
+ f.input_field :age, :as => :integer
69
+ end
70
+
71
+ assert_select 'input[min=18]'
72
+ end
73
+
74
+ test 'builder input_field should use pattern component' do
75
+ with_concat_form_for(@other_validating_user) do |f|
76
+ f.input_field :country, :as => :string
77
+ end
78
+
79
+ assert_select 'input[pattern="\w+"]'
80
+ end
81
+
82
+ test 'builder input_field should use readonly component' do
83
+ with_concat_form_for(@other_validating_user) do |f|
84
+ f.input_field :age, :as => :integer, :readonly => true
85
+ end
86
+
87
+ assert_select 'input.integer.readonly[readonly]'
88
+ end
89
+
90
+ test 'builder input_field should use maxlength component' do
91
+ with_concat_form_for(@validating_user) do |f|
92
+ f.input_field :name, :as => :string
93
+ end
94
+
95
+ assert_select 'input.string[maxlength=25]'
96
+ end
97
+
53
98
  test 'builder collection input_field should generate input tag with a clean HTML' do
54
99
  with_concat_form_for(@user) do |f|
55
100
  f.input_field :status, :collection => ['Open', 'Closed'], :class => 'status', :label_method => :to_s, :value_method => :to_s
@@ -11,6 +11,27 @@ class WrapperTest < ActionView::TestCase
11
11
  assert_no_select 'div.field_with_errors'
12
12
  end
13
13
 
14
+ test 'wrapper should add the attribute name class' do
15
+ with_form_for @user, :name
16
+ assert_select 'div.user_name'
17
+ end
18
+
19
+ test 'wrapper should add the attribute name class for nested forms' do
20
+ @user.company = Company.new(1, 'Empresa')
21
+ with_concat_form_for @user do |f|
22
+ concat(f.simple_fields_for(:company) do |company_form|
23
+ concat(company_form.input :name)
24
+ end)
25
+ end
26
+
27
+ assert_select 'div.user_company_name'
28
+ end
29
+
30
+ test 'wrapper should add the association name class' do
31
+ with_form_for @user, :company
32
+ assert_select 'div.user_company'
33
+ end
34
+
14
35
  test 'wrapper should add error class for attribute with errors' do
15
36
  with_form_for @user, :name
16
37
  assert_select 'div.field_with_errors'
@@ -72,6 +93,7 @@ class WrapperTest < ActionView::TestCase
72
93
  assert_select 'form div.wrapper'
73
94
  assert_no_select 'div.required'
74
95
  assert_no_select 'div.string'
96
+ assert_no_select 'div.user_name'
75
97
  end
76
98
  end
77
99
 
@@ -25,6 +25,14 @@ class SimpleFormGeneratorTest < Rails::Generators::TestCase
25
25
  /config\.default_wrapper = :bootstrap/
26
26
  end
27
27
 
28
+ test 'generates the simple_form initializer with the foundation wrappers' do
29
+ run_generator %w(--foundation)
30
+ assert_file 'config/initializers/simple_form.rb',
31
+ /config\.default_wrapper = :default/, /config\.boolean_style = :nested/
32
+ assert_file 'config/initializers/simple_form_foundation.rb', /config\.wrappers :foundation/,
33
+ /config\.default_wrapper = :foundation/
34
+ end
35
+
28
36
  %W(erb haml slim).each do |engine|
29
37
  test "generates the scaffold template when using #{engine}" do
30
38
  run_generator ['-e', engine]
@@ -91,9 +91,9 @@ class DateTimeInputTest < ActionView::TestCase
91
91
  assert_select 'label[for=project_created_at_4i]'
92
92
  end
93
93
 
94
- test 'date time input should not generate invalid required html attribute' do
94
+ test 'date time input should generate required html attribute' do
95
95
  with_input_for @user, :delivery_time, :time, :required => true
96
96
  assert_select 'select.required'
97
- assert_no_select 'select[required]'
97
+ assert_select 'select[required]'
98
98
  end
99
99
  end
@@ -94,6 +94,21 @@ class GroupedCollectionSelectInputTest < ActionView::TestCase
94
94
  end
95
95
  end
96
96
 
97
+ test 'grouped collection should allow overriding label and value methods using a lambda' do
98
+ with_input_for @user, :tag_ids, :grouped_select,
99
+ :collection => { 'Authors' => ['Jose', 'Carlos'] },
100
+ :group_method => :last,
101
+ :label_method => lambda { |i| i.upcase },
102
+ :value_method => lambda { |i| i.downcase }
103
+
104
+ assert_select 'select.grouped_select#user_tag_ids' do
105
+ assert_select 'optgroup[label=Authors]' do
106
+ assert_select 'option[value=jose]', 'JOSE'
107
+ assert_select 'option[value=carlos]', 'CARLOS'
108
+ end
109
+ end
110
+ end
111
+
97
112
  test 'grouped collection with associations' do
98
113
  tag_groups = [
99
114
  TagGroup.new(1, "Group of Tags", [Tag.new(1, "Tag 1"), Tag.new(2, "Tag 2")]),
@@ -84,6 +84,12 @@ module MiscHelpers
84
84
  end
85
85
  end
86
86
 
87
+ def custom_wrapper_with_wrapped_label_input
88
+ SimpleForm.build :tag => :section, :class => "custom_wrapper", :pattern => false do |b|
89
+ b.use :label_input, :wrap_with => { :tag => :div, :class => :field }
90
+ end
91
+ end
92
+
87
93
  def custom_form_for(object, *args, &block)
88
94
  simple_form_for(object, *(args << { :builder => CustomFormBuilder }), &block)
89
95
  end