simple_form 1.3.1 → 1.4.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.

@@ -1,12 +1,19 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class StringInput < Base
4
+ extend MapType
5
+
6
+ map_type :string, :email, :search, :tel, :url, :to => :text_field
7
+ map_type :password, :to => :password_field
8
+
4
9
  def input
5
10
  input_html_options[:size] ||= [limit, SimpleForm.default_input_size].compact.min
6
- input_html_options[:maxlength] ||= limit if limit
7
- input_html_options[:type] ||= input_type unless string?
11
+ input_html_options[:maxlength] ||= limit if limit && SimpleForm.html5
12
+ if password? || SimpleForm.html5
13
+ input_html_options[:type] ||= input_type unless string?
14
+ end
8
15
 
9
- @builder.text_field(attribute_name, input_html_options)
16
+ @builder.send(input_method, attribute_name, input_html_options)
10
17
  end
11
18
 
12
19
  def input_html_classes
@@ -26,6 +33,10 @@ module SimpleForm
26
33
  def string?
27
34
  input_type == :string
28
35
  end
36
+
37
+ def password?
38
+ input_type == :password
39
+ end
29
40
  end
30
41
  end
31
42
  end
@@ -10,7 +10,7 @@ module SimpleForm
10
10
  def map_type(*types)
11
11
  map_to = types.extract_options![:to]
12
12
  raise ArgumentError, "You need to give :to as option to map_type" unless map_to
13
- types.each { |t| mappings[t] = map_to }
13
+ self.mappings = mappings.merge types.each_with_object({}) { |t, m| m[t] = map_to }
14
14
  end
15
15
  end
16
16
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleForm
2
- VERSION = "1.3.1".freeze
2
+ VERSION = "1.4.0".freeze
3
3
  end
@@ -1,9 +1,11 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class BuilderTest < ActionView::TestCase
4
-
5
- def with_concat_form_for(object, &block)
6
- concat form_for(object, &block)
4
+ def with_custom_form_for(object, *args, &block)
5
+ with_concat_custom_form_for(object) do |f|
6
+ assert f.instance_of?(CustomFormBuilder)
7
+ yield f
8
+ end
7
9
  end
8
10
 
9
11
  def with_collection_radio(object, attribute, collection, value_method, text_method, options={}, html_options={})
@@ -116,10 +118,17 @@ class BuilderTest < ActionView::TestCase
116
118
  assert_select 'form li input[type=radio][value=false]#user_active_false'
117
119
  end
118
120
 
119
- test 'collection radio does not wrap items by default' do
121
+ test 'collection radio wrap items in a span tag by default' do
120
122
  with_collection_radio @user, :active, [true, false], :to_s, :to_s
121
123
 
122
- assert_no_select 'form li'
124
+ assert_select 'form span input[type=radio][value=true]#user_active_true + label'
125
+ assert_select 'form span input[type=radio][value=false]#user_active_false + label'
126
+ end
127
+
128
+ test 'collection radio does not wrap input inside the label' do
129
+ with_collection_radio @user, :active, [true, false], :to_s, :to_s
130
+
131
+ assert_no_select 'form label input'
123
132
  end
124
133
 
125
134
  # COLLECTION CHECK BOX
@@ -259,10 +268,17 @@ class BuilderTest < ActionView::TestCase
259
268
  assert_select 'form li input[type=checkbox][value=false]#user_active_false'
260
269
  end
261
270
 
262
- test 'collection check box does not wrap items by default' do
271
+ test 'collection check box wrap items in a span tag by default' do
272
+ with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s
273
+
274
+ assert_select 'form span input[type=checkbox][value=true]#user_active_true + label'
275
+ assert_select 'form span input[type=checkbox][value=false]#user_active_false + label'
276
+ end
277
+
278
+ test 'collection check box does not wrap input inside the label' do
263
279
  with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s
264
280
 
265
- assert_no_select 'form li'
281
+ assert_no_select 'form label input'
266
282
  end
267
283
 
268
284
  # SIMPLE FIELDS
@@ -273,4 +289,20 @@ class BuilderTest < ActionView::TestCase
273
289
  end
274
290
  end
275
291
  end
292
+
293
+ test 'fields for yields an instance of CustomBuilder if main builder is a CustomBuilder' do
294
+ with_custom_form_for(:user) do |f|
295
+ f.simple_fields_for(:company) do |company|
296
+ assert company.instance_of?(CustomFormBuilder)
297
+ end
298
+ end
299
+ end
300
+
301
+ test 'fields for yields an instance of FormBuilder if it was set in options' do
302
+ with_custom_form_for(:user) do |f|
303
+ f.simple_fields_for(:company, :builder => SimpleForm::FormBuilder) do |company|
304
+ assert company.instance_of?(SimpleForm::FormBuilder)
305
+ end
306
+ end
307
+ end
276
308
  end
@@ -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'
@@ -205,4 +242,11 @@ class LabelTest < ActionView::TestCase
205
242
  with_label_for :project, :description, :string, :required => false
206
243
  assert_no_select 'label.required[for=project_description]'
207
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
208
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
@@ -27,6 +27,12 @@ class FormBuilderTest < ActionView::TestCase
27
27
  end
28
28
  end
29
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
+
30
36
  def with_hint_for(object, *args)
31
37
  with_concat_form_for(object) do |f|
32
38
  f.hint(*args)
@@ -186,6 +192,14 @@ class FormBuilderTest < ActionView::TestCase
186
192
  assert_select 'form input#user_avatar.file'
187
193
  end
188
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
+
189
203
  test 'build should generate select if a collection is given' do
190
204
  with_form_for @user, :age, :collection => 1..60
191
205
  assert_select 'form select#user_age.select'
@@ -206,6 +220,13 @@ class FormBuilderTest < ActionView::TestCase
206
220
  end
207
221
 
208
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
+
209
230
  test 'builder should allow passing options to input' do
210
231
  with_form_for @user, :name, :input_html => { :class => 'my_input', :id => 'my_input' }
211
232
  assert_select 'form input#my_input.my_input.string'
@@ -362,6 +383,43 @@ class FormBuilderTest < ActionView::TestCase
362
383
  assert_select 'form div.input.required.string.field_with_errors'
363
384
  end
364
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
+
365
423
  # WITHOUT OBJECT
366
424
  test 'builder should generate properly when object is not present' do
367
425
  with_form_for :project, :name
@@ -403,6 +461,22 @@ class FormBuilderTest < ActionView::TestCase
403
461
  assert_select 'span.error#name_error', "can't be blank"
404
462
  end
405
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
+
406
480
  # HINTS
407
481
  test 'builder should generate a hint tag for the attribute' do
408
482
  store_translations(:en, :simple_form => { :hints => { :user => { :name => "Add your name" }}}) do
@@ -511,6 +585,36 @@ class FormBuilderTest < ActionView::TestCase
511
585
  end
512
586
  end
513
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
+
514
618
  # ASSOCIATIONS - BELONGS TO
515
619
  test 'builder creates a select for belongs_to associations' do
516
620
  with_association_for @user, :company
@@ -611,4 +715,81 @@ class FormBuilderTest < ActionView::TestCase
611
715
  with_custom_form_for @user, :email
612
716
  assert_select 'form input[type=email]#user_email.custom'
613
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
614
795
  end