simple_form 1.3.0 → 1.4.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.
Files changed (39) hide show
  1. data/.gitignore +2 -0
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.rdoc +109 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +82 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.rdoc +73 -12
  9. data/Rakefile +27 -0
  10. data/lib/generators/simple_form/templates/_form.html.erb +1 -1
  11. data/lib/generators/simple_form/templates/_form.html.haml +2 -10
  12. data/lib/generators/simple_form/templates/_form.html.slim +10 -0
  13. data/lib/generators/simple_form/templates/simple_form.rb +20 -4
  14. data/lib/simple_form/action_view_extensions/builder.rb +39 -15
  15. data/lib/simple_form/action_view_extensions/form_helper.rb +5 -5
  16. data/lib/simple_form/components/errors.rb +5 -1
  17. data/lib/simple_form/components/labels.rb +2 -2
  18. data/lib/simple_form/form_builder.rb +131 -38
  19. data/lib/simple_form/inputs/base.rb +52 -6
  20. data/lib/simple_form/inputs/collection_input.rb +5 -1
  21. data/lib/simple_form/inputs/date_time_input.rb +4 -0
  22. data/lib/simple_form/inputs/mapping_input.rb +0 -6
  23. data/lib/simple_form/inputs/numeric_input.rb +15 -7
  24. data/lib/simple_form/inputs/priority_input.rb +5 -1
  25. data/lib/simple_form/inputs/string_input.rb +14 -3
  26. data/lib/simple_form/map_type.rb +6 -3
  27. data/lib/simple_form/version.rb +1 -1
  28. data/lib/simple_form.rb +28 -1
  29. data/simple_form.gemspec +22 -0
  30. data/test/action_view_extensions/builder_test.rb +39 -7
  31. data/test/action_view_extensions/form_helper_test.rb +12 -0
  32. data/test/components/label_test.rb +54 -0
  33. data/test/discovery_inputs.rb +21 -0
  34. data/test/form_builder_test.rb +230 -0
  35. data/test/inputs_test.rb +234 -14
  36. data/test/support/misc_helpers.rb +26 -0
  37. data/test/support/models.rb +41 -3
  38. data/test/test_helper.rb +13 -4
  39. metadata +24 -27
@@ -13,6 +13,18 @@ class FormHelperTest < ActionView::TestCase
13
13
  assert_select 'form.simple_form'
14
14
  end
15
15
 
16
+ test 'simple form should use default browser validations by default' do
17
+ concat(simple_form_for(:user) do |f| end)
18
+ assert_no_select 'form[novalidate]'
19
+ end
20
+
21
+ test 'simple form should not use default browser validations if specified in the configuration options' do
22
+ swap SimpleForm, :browser_validations => false do
23
+ concat(simple_form_for(:user) do |f| end)
24
+ assert_select 'form[novalidate="novalidate"]'
25
+ end
26
+ end
27
+
16
28
  test 'simple form should add object name as css class to form when object is not present' do
17
29
  concat(simple_form_for(:user) do |f| end)
18
30
  assert_select 'form.simple_form.user'
@@ -96,6 +96,43 @@ class LabelTest < ActionView::TestCase
96
96
  end
97
97
  end
98
98
 
99
+ test 'label should do correct i18n lookup for nested models with nested translation' do
100
+ @user.company = Company.new(1, 'Empresa')
101
+
102
+ store_translations(:en, :simple_form => { :labels => {
103
+ :user => { :name => 'Usuario', :company => { :name => 'Nome da empresa' } }
104
+ } } ) do
105
+ with_concat_form_for @user do |f|
106
+ concat f.input :name
107
+ concat(f.simple_fields_for(:company) do |company_form|
108
+ concat(company_form.input :name)
109
+ end)
110
+ end
111
+
112
+ assert_select 'label[for=user_name]', /Usuario/
113
+ assert_select 'label[for=user_company_attributes_name]', /Nome da empresa/
114
+ end
115
+ end
116
+
117
+ test 'label should do correct i18n lookup for nested models with no nested translation' do
118
+ @user.company = Company.new(1, 'Empresa')
119
+
120
+ store_translations(:en, :simple_form => { :labels => {
121
+ :user => { :name => 'Usuario' },
122
+ :company => { :name => 'Nome da empresa' }
123
+ } } ) do
124
+ with_concat_form_for @user do |f|
125
+ concat f.input :name
126
+ concat(f.simple_fields_for(:company) do |company_form|
127
+ concat(company_form.input :name)
128
+ end)
129
+ end
130
+
131
+ assert_select 'label[for=user_name]', /Usuario/
132
+ assert_select 'label[for=user_company_attributes_name]', /Nome da empresa/
133
+ end
134
+ end
135
+
99
136
  test 'label should have css class from type' do
100
137
  with_label_for @user, :name, :string
101
138
  assert_select 'label.string'
@@ -170,6 +207,16 @@ class LabelTest < ActionView::TestCase
170
207
  assert_select 'label[for=my_new_id]'
171
208
  end
172
209
 
210
+ test 'label should allow overwriting of for attribute' do
211
+ with_label_for @user, :name, :string, :label_html => { :for => 'my_new_id' }
212
+ assert_select 'label[for=my_new_id]'
213
+ end
214
+
215
+ test 'label should allow overwriting of for attribute with input_html not containing id' do
216
+ with_label_for @user, :name, :string, :label_html => { :for => 'my_new_id' }, :input_html => {:class => 'foo'}
217
+ assert_select 'label[for=my_new_id]'
218
+ end
219
+
173
220
  test 'label should use default input id when it was not overridden' do
174
221
  with_label_for @user, :name, :string, :input_html => { :class => 'my_new_id' }
175
222
  assert_select 'label[for=user_name]'
@@ -195,4 +242,11 @@ class LabelTest < ActionView::TestCase
195
242
  with_label_for :project, :description, :string, :required => false
196
243
  assert_no_select 'label.required[for=project_description]'
197
244
  end
245
+
246
+ test 'label should add chosen label class' do
247
+ swap SimpleForm, :label_class => :my_custom_class do
248
+ with_label_for @user, :name, :string
249
+ assert_select 'label.my_custom_class'
250
+ end
251
+ end
198
252
  end
@@ -0,0 +1,21 @@
1
+ class StringInput < SimpleForm::Inputs::StringInput
2
+ def input
3
+ "<section>#{super}</section>".html_safe
4
+ end
5
+ end
6
+
7
+ class NumericInput < SimpleForm::Inputs::NumericInput
8
+ def input
9
+ "<section>#{super}</section>".html_safe
10
+ end
11
+ end
12
+
13
+ class CustomizedInput < SimpleForm::Inputs::StringInput
14
+ def input
15
+ "<section>#{super}</section>".html_safe
16
+ end
17
+
18
+ def input_method
19
+ :text_field
20
+ end
21
+ end
@@ -9,6 +9,12 @@ class FormBuilderTest < ActionView::TestCase
9
9
  end
10
10
  end
11
11
 
12
+ def with_custom_form_for(object, *args, &block)
13
+ with_concat_custom_form_for(object) do |f|
14
+ f.input(*args, &block)
15
+ end
16
+ end
17
+
12
18
  def with_button_for(object, *args)
13
19
  with_concat_form_for(object) do |f|
14
20
  f.button(*args)
@@ -21,6 +27,12 @@ class FormBuilderTest < ActionView::TestCase
21
27
  end
22
28
  end
23
29
 
30
+ def with_full_error_for(object, *args)
31
+ with_concat_form_for(object) do |f|
32
+ f.full_error(*args)
33
+ end
34
+ end
35
+
24
36
  def with_hint_for(object, *args)
25
37
  with_concat_form_for(object) do |f|
26
38
  f.hint(*args)
@@ -70,6 +82,14 @@ class FormBuilderTest < ActionView::TestCase
70
82
  end
71
83
  end
72
84
 
85
+ test 'builder should allow adding custom input mappings for integer input types' do
86
+ swap SimpleForm, :input_mappings => { /lock_version/ => :hidden } do
87
+ with_form_for @user, :lock_version
88
+ assert_no_select 'form input#user_lock_version.integer'
89
+ assert_select 'form input#user_lock_version.hidden'
90
+ end
91
+ end
92
+
73
93
  test 'builder uses the first matching custom input map when more than one match' do
74
94
  swap SimpleForm, :input_mappings => { /count$/ => :integer, /^post_/ => :password } do
75
95
  with_form_for @user, :post_count
@@ -78,6 +98,14 @@ class FormBuilderTest < ActionView::TestCase
78
98
  end
79
99
  end
80
100
 
101
+ test 'builder uses the custom map only for matched attributes' do
102
+ swap SimpleForm, :input_mappings => { /lock_version/ => :hidden } do
103
+ with_form_for @user, :post_count
104
+ assert_no_select 'form input#user_post_count.hidden'
105
+ assert_select 'form input#user_post_count.string'
106
+ end
107
+ end
108
+
81
109
  # INPUT TYPES
82
110
  test 'builder should generate text fields for string columns' do
83
111
  with_form_for @user, :name
@@ -164,6 +192,14 @@ class FormBuilderTest < ActionView::TestCase
164
192
  assert_select 'form input#user_avatar.file'
165
193
  end
166
194
 
195
+ test 'builder should generate file for attributes that are real db columns but have file methods' do
196
+ @user.home_picture = mock("file")
197
+ @user.home_picture.expects(:respond_to?).with(:mounted_as).returns(true)
198
+
199
+ with_form_for @user, :home_picture
200
+ assert_select 'form input#user_home_picture.file'
201
+ end
202
+
167
203
  test 'build should generate select if a collection is given' do
168
204
  with_form_for @user, :age, :collection => 1..60
169
205
  assert_select 'form select#user_age.select'
@@ -184,6 +220,13 @@ class FormBuilderTest < ActionView::TestCase
184
220
  end
185
221
 
186
222
  # COMMON OPTIONS
223
+ test 'builder should add chosen form class' do
224
+ swap SimpleForm, :form_class => :my_custom_class do
225
+ with_form_for @user, :name
226
+ assert_select 'form.my_custom_class'
227
+ end
228
+ end
229
+
187
230
  test 'builder should allow passing options to input' do
188
231
  with_form_for @user, :name, :input_html => { :class => 'my_input', :id => 'my_input' }
189
232
  assert_select 'form input#my_input.my_input.string'
@@ -340,6 +383,43 @@ class FormBuilderTest < ActionView::TestCase
340
383
  assert_select 'form div.input.required.string.field_with_errors'
341
384
  end
342
385
 
386
+ # ONLY THE INPUT TAG
387
+ test "builder input_field should only render the input tag, nothing else" do
388
+ with_concat_form_for(@user) do |f|
389
+ f.input_field :name
390
+ end
391
+ assert_select 'form > input.required.string'
392
+ assert_no_select 'div.string'
393
+ assert_no_select 'label'
394
+ assert_no_select '.hint'
395
+ end
396
+
397
+ test 'builder input_field should allow overriding default input type' do
398
+ with_concat_form_for(@user) do |f|
399
+ f.input_field :name, :as => :text
400
+ end
401
+
402
+ assert_no_select 'input#user_name'
403
+ assert_select 'textarea#user_name.text'
404
+ end
405
+
406
+ test 'builder input_field should allow passing options to input tag' do
407
+ with_concat_form_for(@user) do |f|
408
+ f.input_field :name, :id => 'name_input', :class => 'name'
409
+ end
410
+
411
+ assert_select 'input.string.name#name_input'
412
+ end
413
+
414
+ test 'builder input_field should generate an input tag with a clean HTML' do
415
+ with_concat_form_for(@user) do |f|
416
+ f.input_field :name, :as => :integer, :class => 'name'
417
+ end
418
+
419
+ assert_no_select 'input.integer[input_html]'
420
+ assert_no_select 'input.integer[as]'
421
+ end
422
+
343
423
  # WITHOUT OBJECT
344
424
  test 'builder should generate properly when object is not present' do
345
425
  with_form_for :project, :name
@@ -371,11 +451,32 @@ class FormBuilderTest < ActionView::TestCase
371
451
  assert_select 'span.error', "can't be blank"
372
452
  end
373
453
 
454
+ test 'builder should generate an error tag with a clean HTML' do
455
+ with_error_for @user, :name
456
+ assert_no_select 'span.error[error_html]'
457
+ end
458
+
374
459
  test 'builder should allow passing options to error tag' do
375
460
  with_error_for @user, :name, :id => 'name_error'
376
461
  assert_select 'span.error#name_error', "can't be blank"
377
462
  end
378
463
 
464
+ # FULL ERRORS
465
+ test 'builder should generate an full error tag for the attribute' do
466
+ with_full_error_for @user, :name
467
+ assert_select 'span.error', "Super User Name! can't be blank"
468
+ end
469
+
470
+ test 'builder should generate an full error tag with a clean HTML' do
471
+ with_full_error_for @user, :name
472
+ assert_no_select 'span.error[error_html]'
473
+ end
474
+
475
+ test 'builder should allow passing options to full error tag' do
476
+ with_full_error_for @user, :name, :id => 'name_error', :error_prefix => "Your name"
477
+ assert_select 'span.error#name_error', "Your name can't be blank"
478
+ end
479
+
379
480
  # HINTS
380
481
  test 'builder should generate a hint tag for the attribute' do
381
482
  store_translations(:en, :simple_form => { :hints => { :user => { :name => "Add your name" }}}) do
@@ -384,11 +485,22 @@ class FormBuilderTest < ActionView::TestCase
384
485
  end
385
486
  end
386
487
 
488
+ test 'builder should generate a hint component tag for the given text for a model with ActiveModel::Validations' do
489
+ with_hint_for @validating_user, 'Hello World!'
490
+ assert_select 'span.hint', 'Hello World!'
491
+ end
492
+
387
493
  test 'builder should generate a hint component tag for the given text' do
388
494
  with_hint_for @user, 'Hello World!'
389
495
  assert_select 'span.hint', 'Hello World!'
390
496
  end
391
497
 
498
+ test 'builder should generate a hint componet tag with a clean HTML' do
499
+ with_hint_for @validating_user, 'Hello World!'
500
+ assert_no_select 'span.hint[hint]'
501
+ assert_no_select 'span.hint[hint_html]'
502
+ end
503
+
392
504
  test 'builder should allow passing options to hint tag' do
393
505
  with_hint_for @user, :name, :hint => 'Hello World!', :id => 'name_hint'
394
506
  assert_select 'span.hint#name_hint', 'Hello World!'
@@ -400,6 +512,11 @@ class FormBuilderTest < ActionView::TestCase
400
512
  assert_select 'label.string[for=user_name]', /Name/
401
513
  end
402
514
 
515
+ test 'builder should generate a label componet tag with a clean HTML' do
516
+ with_label_for @user, :name
517
+ assert_no_select 'label.string[label_html]'
518
+ end
519
+
403
520
  test 'builder should add a required class to label if the attribute is required' do
404
521
  with_label_for @validating_user, :name
405
522
  assert_select 'label.string.required[for=validating_user_name]', /Name/
@@ -468,6 +585,36 @@ class FormBuilderTest < ActionView::TestCase
468
585
  end
469
586
  end
470
587
 
588
+ test 'builder preloads collection association' do
589
+ value = @user.tags
590
+ value.expects(:to_a).returns(value)
591
+ with_association_for @user, :tags
592
+ assert_select 'form select.select#user_tag_ids'
593
+ assert_select 'form select option[value=1]', 'Tag 1'
594
+ assert_select 'form select option[value=2]', 'Tag 2'
595
+ assert_select 'form select option[value=3]', 'Tag 3'
596
+ end
597
+
598
+ test 'builder does not preload collection association if preload false' do
599
+ value = @user.company
600
+ value.expects(:to_a).never
601
+ with_association_for @user, :company, :preload => false
602
+ assert_select 'form select.select#user_company_id'
603
+ assert_select 'form select option[value=1]', 'Company 1'
604
+ assert_select 'form select option[value=2]', 'Company 2'
605
+ assert_select 'form select option[value=3]', 'Company 3'
606
+ end
607
+
608
+ test 'builder does not preload non collection association' do
609
+ value = @user.company
610
+ value.expects(:to_a).never
611
+ with_association_for @user, :company, :preload => false
612
+ assert_select 'form select.select#user_company_id'
613
+ assert_select 'form select option[value=1]', 'Company 1'
614
+ assert_select 'form select option[value=2]', 'Company 2'
615
+ assert_select 'form select option[value=3]', 'Company 3'
616
+ end
617
+
471
618
  # ASSOCIATIONS - BELONGS TO
472
619
  test 'builder creates a select for belongs_to associations' do
473
620
  with_association_for @user, :company
@@ -562,4 +709,87 @@ class FormBuilderTest < ActionView::TestCase
562
709
  assert_select 'form ul', :count => 1
563
710
  assert_select 'form ul li', :count => 3
564
711
  end
712
+
713
+ # CUSTOM FORM BUILDER
714
+ test 'custom builder should inherit mappings' do
715
+ with_custom_form_for @user, :email
716
+ assert_select 'form input[type=email]#user_email.custom'
717
+ end
718
+
719
+ test 'form with CustomMapTypeFormBuilder should use custom map type builder' do
720
+ with_concat_custom_mapping_form_for(:user) do |user|
721
+ assert user.instance_of?(CustomMapTypeFormBuilder)
722
+ end
723
+ end
724
+
725
+ test 'form with CustomMapTypeFormBuilder should use custom mapping' do
726
+ with_concat_custom_mapping_form_for(:user) do |user|
727
+ assert_equal SimpleForm::Inputs::StringInput, user.class.mappings[:custom_type]
728
+ end
729
+ end
730
+
731
+ test 'form without CustomMapTypeFormBuilder should not use custom mapping' do
732
+ with_concat_form_for(:user) do |user|
733
+ assert_nil user.class.mappings[:custom_type]
734
+ end
735
+ end
736
+
737
+ # DISCOVERY
738
+ # Setup new inputs and remove them after the test.
739
+ def discovery(value=false)
740
+ swap SimpleForm, :cache_discovery => value do
741
+ begin
742
+ load "discovery_inputs.rb"
743
+ yield
744
+ ensure
745
+ SimpleForm::FormBuilder.discovery_cache.clear
746
+ Object.send :remove_const, :StringInput
747
+ Object.send :remove_const, :NumericInput
748
+ Object.send :remove_const, :CustomizedInput
749
+ end
750
+ end
751
+ end
752
+
753
+ test 'builder should not discover new inputs if cached' do
754
+ with_form_for @user, :name
755
+ assert_select 'form input#user_name.string'
756
+
757
+ discovery(true) do
758
+ with_form_for @user, :name
759
+ assert_no_select 'form section input#user_name.string'
760
+ end
761
+ end
762
+
763
+ test 'builder should discover new inputs' do
764
+ discovery do
765
+ with_form_for @user, :name, :as => :customized
766
+ assert_select 'form section input#user_name.string'
767
+ end
768
+ end
769
+
770
+ test 'builder should not discover new inputs if discovery is off' do
771
+ with_form_for @user, :name
772
+ assert_select 'form input#user_name.string'
773
+
774
+ swap SimpleForm, :inputs_discovery => false do
775
+ discovery do
776
+ with_form_for @user, :name
777
+ assert_no_select 'form section input#user_name.string'
778
+ end
779
+ end
780
+ end
781
+
782
+ test 'builder should discover new inputs from mappings if not cached' do
783
+ discovery do
784
+ with_form_for @user, :name
785
+ assert_select 'form section input#user_name.string'
786
+ end
787
+ end
788
+
789
+ test 'builder should discover new inputs from internal fallbacks if not cached' do
790
+ discovery do
791
+ with_form_for @user, :age
792
+ assert_select 'form section input#user_age.numeric.integer'
793
+ end
794
+ end
565
795
  end