simple_form 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

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