simple_form_awesome 2.2.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 (103) hide show
  1. data/CHANGELOG.md +327 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +25 -0
  4. data/lib/generators/simple_form/USAGE +3 -0
  5. data/lib/generators/simple_form/install_generator.rb +48 -0
  6. data/lib/generators/simple_form/templates/AUI_README +19 -0
  7. data/lib/generators/simple_form/templates/README +12 -0
  8. data/lib/generators/simple_form/templates/_form.html.erb +13 -0
  9. data/lib/generators/simple_form/templates/_form.html.haml +10 -0
  10. data/lib/generators/simple_form/templates/_form.html.slim +10 -0
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +142 -0
  12. data/lib/generators/simple_form/templates/config/initializers/simple_form_aui.rb +21 -0
  13. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +45 -0
  14. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +26 -0
  15. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +26 -0
  16. data/lib/simple_form/action_view_extensions/builder.rb +340 -0
  17. data/lib/simple_form/action_view_extensions/form_helper.rb +72 -0
  18. data/lib/simple_form/components/errors.rb +35 -0
  19. data/lib/simple_form/components/hints.rb +18 -0
  20. data/lib/simple_form/components/html5.rb +26 -0
  21. data/lib/simple_form/components/label_input.rb +15 -0
  22. data/lib/simple_form/components/labels.rb +79 -0
  23. data/lib/simple_form/components/maxlength.rb +41 -0
  24. data/lib/simple_form/components/min_max.rb +50 -0
  25. data/lib/simple_form/components/pattern.rb +34 -0
  26. data/lib/simple_form/components/placeholders.rb +16 -0
  27. data/lib/simple_form/components/readonly.rb +22 -0
  28. data/lib/simple_form/components.rb +20 -0
  29. data/lib/simple_form/core_ext/hash.rb +16 -0
  30. data/lib/simple_form/error_notification.rb +48 -0
  31. data/lib/simple_form/form_builder.rb +482 -0
  32. data/lib/simple_form/helpers/autofocus.rb +11 -0
  33. data/lib/simple_form/helpers/disabled.rb +15 -0
  34. data/lib/simple_form/helpers/readonly.rb +15 -0
  35. data/lib/simple_form/helpers/required.rb +35 -0
  36. data/lib/simple_form/helpers/validators.rb +44 -0
  37. data/lib/simple_form/helpers.rb +12 -0
  38. data/lib/simple_form/i18n_cache.rb +22 -0
  39. data/lib/simple_form/inputs/aui_string_input.rb +10 -0
  40. data/lib/simple_form/inputs/base.rb +184 -0
  41. data/lib/simple_form/inputs/block_input.rb +14 -0
  42. data/lib/simple_form/inputs/boolean_input.rb +78 -0
  43. data/lib/simple_form/inputs/collection_check_boxes_input.rb +21 -0
  44. data/lib/simple_form/inputs/collection_input.rb +101 -0
  45. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +63 -0
  46. data/lib/simple_form/inputs/collection_select_input.rb +14 -0
  47. data/lib/simple_form/inputs/date_time_input.rb +28 -0
  48. data/lib/simple_form/inputs/file_input.rb +9 -0
  49. data/lib/simple_form/inputs/grouped_collection_select_input.rb +41 -0
  50. data/lib/simple_form/inputs/hidden_input.rb +17 -0
  51. data/lib/simple_form/inputs/numeric_input.rb +24 -0
  52. data/lib/simple_form/inputs/password_input.rb +12 -0
  53. data/lib/simple_form/inputs/priority_input.rb +24 -0
  54. data/lib/simple_form/inputs/range_input.rb +14 -0
  55. data/lib/simple_form/inputs/string_input.rb +23 -0
  56. data/lib/simple_form/inputs/text_area_input.rb +12 -0
  57. data/lib/simple_form/inputs/text_input.rb +11 -0
  58. data/lib/simple_form/inputs.rb +23 -0
  59. data/lib/simple_form/map_type.rb +16 -0
  60. data/lib/simple_form/version.rb +3 -0
  61. data/lib/simple_form/wrappers/builder.rb +103 -0
  62. data/lib/simple_form/wrappers/many.rb +73 -0
  63. data/lib/simple_form/wrappers/root.rb +36 -0
  64. data/lib/simple_form/wrappers/single.rb +24 -0
  65. data/lib/simple_form/wrappers.rb +8 -0
  66. data/lib/simple_form.rb +221 -0
  67. data/test/action_view_extensions/builder_test.rb +583 -0
  68. data/test/action_view_extensions/form_helper_test.rb +143 -0
  69. data/test/components/label_test.rb +327 -0
  70. data/test/form_builder/association_test.rb +186 -0
  71. data/test/form_builder/button_test.rb +47 -0
  72. data/test/form_builder/error_notification_test.rb +79 -0
  73. data/test/form_builder/error_test.rb +121 -0
  74. data/test/form_builder/general_test.rb +402 -0
  75. data/test/form_builder/hint_test.rb +138 -0
  76. data/test/form_builder/input_field_test.rb +63 -0
  77. data/test/form_builder/label_test.rb +71 -0
  78. data/test/form_builder/wrapper_test.rb +203 -0
  79. data/test/generators/simple_form_generator_test.rb +42 -0
  80. data/test/inputs/boolean_input_test.rb +140 -0
  81. data/test/inputs/collection_check_boxes_input_test.rb +224 -0
  82. data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
  83. data/test/inputs/collection_select_input_test.rb +241 -0
  84. data/test/inputs/datetime_input_test.rb +99 -0
  85. data/test/inputs/disabled_test.rb +78 -0
  86. data/test/inputs/discovery_test.rb +69 -0
  87. data/test/inputs/file_input_test.rb +16 -0
  88. data/test/inputs/general_test.rb +116 -0
  89. data/test/inputs/grouped_collection_select_input_test.rb +118 -0
  90. data/test/inputs/hidden_input_test.rb +30 -0
  91. data/test/inputs/numeric_input_test.rb +173 -0
  92. data/test/inputs/priority_input_test.rb +43 -0
  93. data/test/inputs/readonly_test.rb +101 -0
  94. data/test/inputs/required_test.rb +113 -0
  95. data/test/inputs/string_input_test.rb +146 -0
  96. data/test/inputs/text_input_test.rb +24 -0
  97. data/test/simple_form_test.rb +9 -0
  98. data/test/support/discovery_inputs.rb +27 -0
  99. data/test/support/misc_helpers.rb +138 -0
  100. data/test/support/mock_controller.rb +24 -0
  101. data/test/support/models.rb +216 -0
  102. data/test/test_helper.rb +95 -0
  103. metadata +217 -0
@@ -0,0 +1,146 @@
1
+ # encoding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class StringInputTest < ActionView::TestCase
5
+ test 'input should map text field to string attribute' do
6
+ with_input_for @user, :name, :string
7
+ assert_select "input#user_name[type=text][name='user[name]'][value=New in SimpleForm!]"
8
+ end
9
+
10
+ test 'input should generate a password field for password attributes' do
11
+ with_input_for @user, :password, :password
12
+ assert_select "input#user_password.password[type=password][name='user[password]']"
13
+ end
14
+
15
+ test 'input should not use size attribute for decimal attributes' do
16
+ with_input_for @user, :credit_limit, :decimal
17
+ assert_no_select 'input.decimal[size]'
18
+ end
19
+
20
+ test 'input should get maxlength from column definition for string attributes' do
21
+ with_input_for @user, :name, :string
22
+ assert_select 'input.string[maxlength=100]'
23
+ end
24
+
25
+ test 'input should not get maxlength from column without size definition for string attributes' do
26
+ with_input_for @user, :action, :string
27
+ assert_no_select 'input.string[maxlength]'
28
+ end
29
+
30
+ test 'input should get size from column definition for string attributes respecting maximum value' do
31
+ with_input_for @user, :name, :string
32
+ assert_select 'input.string[size=50]'
33
+ end
34
+
35
+ test 'input should use default text size for password attributes' do
36
+ with_input_for @user, :password, :password
37
+ assert_select 'input.password[type=password][size=50]'
38
+ end
39
+
40
+ test 'input should get maxlength from column definition for password attributes' do
41
+ with_input_for @user, :password, :password
42
+ assert_select 'input.password[type=password][maxlength=100]'
43
+ end
44
+
45
+ test 'input should infer maxlength column definition from validation when present' do
46
+ with_input_for @validating_user, :name, :string
47
+ assert_select 'input.string[maxlength=25]'
48
+ end
49
+
50
+ test 'input should not get maxlength from validation when tokenizer present' do
51
+ with_input_for @validating_user, :action, :string
52
+ assert_no_select 'input.string[maxlength]'
53
+ end
54
+
55
+ test 'input should get maxlength from validation when :is option present' do
56
+ with_input_for @validating_user, :home_picture, :string
57
+ assert_select 'input.string[maxlength=12]'
58
+ end
59
+
60
+ test 'input size and maxlength should be the column limit plus one to make room for decimal point' do
61
+ with_input_for @user, :credit_limit, :string
62
+
63
+ assert_select "input.string[maxlength=16][size=16]"
64
+ end
65
+
66
+ test 'input should not generate placeholder by default' do
67
+ with_input_for @user, :name, :string
68
+ assert_no_select 'input[placeholder]'
69
+ end
70
+
71
+ test 'input should accept the placeholder option' do
72
+ with_input_for @user, :name, :string, :placeholder => 'Put in some text'
73
+ assert_select 'input.string[placeholder=Put in some text]'
74
+ end
75
+
76
+ test 'input should generate a password field for password attributes that accept placeholder' do
77
+ with_input_for @user, :password, :password, :placeholder => 'Password Confirmation'
78
+ assert_select 'input[type=password].password[placeholder=Password Confirmation]#user_password'
79
+ end
80
+
81
+ test 'input should not infer pattern from attributes by default' do
82
+ with_input_for @other_validating_user, :country, :string
83
+ assert_no_select 'input[pattern="\w+"]'
84
+ end
85
+
86
+ test 'input should infer pattern from attributes' do
87
+ with_input_for @other_validating_user, :country, :string, :pattern => true
88
+ assert_select 'input[pattern="\w+"]'
89
+ end
90
+
91
+ test 'input should infer pattern from attributes using proc' do
92
+ with_input_for @other_validating_user, :name, :string, :pattern => true
93
+ assert_select 'input[pattern="\w+"]'
94
+ end
95
+
96
+ test 'input should not infer pattern from attributes if root default is false' do
97
+ swap_wrapper do
98
+ with_input_for @other_validating_user, :country, :string
99
+ assert_no_select 'input[pattern="\w+"]'
100
+ end
101
+ end
102
+
103
+ test 'input should use given pattern from attributes' do
104
+ with_input_for @other_validating_user, :country, :string, :input_html => { :pattern => "\\d+" }
105
+ assert_select 'input[pattern="\d+"]'
106
+ end
107
+
108
+ test 'input should use i18n to translate placeholder text' do
109
+ store_translations(:en, :simple_form => { :placeholders => { :user => {
110
+ :name => 'Name goes here'
111
+ } } }) do
112
+ with_input_for @user, :name, :string
113
+ assert_select 'input.string[placeholder=Name goes here]'
114
+ end
115
+ end
116
+
117
+ [:email, :url, :search, :tel].each do |type|
118
+ test "input should allow type #{type}" do
119
+ with_input_for @user, :name, type
120
+ assert_select "input.string.#{type}"
121
+ assert_select "input[type=#{type}]"
122
+ end
123
+
124
+ test "input should not allow type #{type} if HTML5 compatibility is disabled" do
125
+ swap_wrapper do
126
+ with_input_for @user, :name, type
127
+ assert_select "input[type=text]"
128
+ assert_no_select "input[type=#{type}]"
129
+ end
130
+ end
131
+ end
132
+
133
+ test 'input strips extra spaces from class html attribute with default classes' do
134
+ with_input_for @user, :name, :string
135
+ assert_select "input[class='string required']"
136
+ assert_no_select "input[class='string required ']"
137
+ assert_no_select "input[class=' string required']"
138
+ end
139
+
140
+ test 'input strips extra spaces from class html attribute when giving a custom class' do
141
+ with_input_for @user, :name, :string, :input_html => { :class => "my_input" }
142
+ assert_select "input[class='string required my_input']"
143
+ assert_no_select "input[class='string required my_input ']"
144
+ assert_no_select "input[class=' string required my_input']"
145
+ end
146
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class TextInputTest < ActionView::TestCase
5
+ test 'input should generate a text area for text attributes' do
6
+ with_input_for @user, :description, :text
7
+ assert_select 'textarea.text#user_description'
8
+ end
9
+
10
+ test 'input should generate a text area for text attributes that accept placeholder' do
11
+ with_input_for @user, :description, :text, :placeholder => 'Put in some text'
12
+ assert_select 'textarea.text[placeholder=Put in some text]'
13
+ end
14
+
15
+ test 'input should get maxlength from column definition for text attributes' do
16
+ with_input_for @user, :description, :text
17
+ assert_select 'textarea.text[maxlength=200]'
18
+ end
19
+
20
+ test 'input should infer maxlength column definition from validation when present for text attributes' do
21
+ with_input_for @validating_user, :description, :text
22
+ assert_select 'textarea.text[maxlength=50]'
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class SimpleFormTest < ActiveSupport::TestCase
4
+ test 'setup block yields self' do
5
+ SimpleForm.setup do |config|
6
+ assert_equal SimpleForm, config
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
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
22
+
23
+ class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput
24
+ def input_html_classes
25
+ super.push('chosen')
26
+ end
27
+ end
@@ -0,0 +1,138 @@
1
+ module MiscHelpers
2
+ def store_translations(locale, translations, &block)
3
+ I18n.backend.store_translations locale, translations
4
+ yield
5
+ ensure
6
+ I18n.reload!
7
+ I18n.backend.send :init_translations
8
+ end
9
+
10
+ def assert_no_select(selector, value = nil)
11
+ assert_select(selector, :text => value, :count => 0)
12
+ end
13
+
14
+ def swap(object, new_values)
15
+ old_values = {}
16
+ new_values.each do |key, value|
17
+ old_values[key] = object.send key
18
+ object.send :"#{key}=", value
19
+ end
20
+ yield
21
+ ensure
22
+ old_values.each do |key, value|
23
+ object.send :"#{key}=", value
24
+ end
25
+ end
26
+
27
+ def swap_wrapper(name=:default, wrapper=self.custom_wrapper)
28
+ old = SimpleForm.wrappers[name]
29
+ SimpleForm.wrappers[name] = wrapper
30
+ yield
31
+ ensure
32
+ SimpleForm.wrappers[name] = old
33
+ end
34
+
35
+ def custom_wrapper
36
+ SimpleForm.build :tag => :section, :class => "custom_wrapper", :pattern => false do |b|
37
+ b.use :pattern
38
+ b.wrapper :another, :class => "another_wrapper" do |ba|
39
+ ba.use :label
40
+ ba.use :input
41
+ end
42
+ b.wrapper :error_wrapper, :tag => :div, :class => "error_wrapper" do |be|
43
+ be.use :error, :wrap_with => { :tag => :span, :class => "omg_error" }
44
+ end
45
+ b.use :hint, :wrap_with => { :class => "omg_hint" }
46
+ end
47
+ end
48
+
49
+ def custom_wrapper_with_wrapped_input
50
+ SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
51
+ b.wrapper :tag => :div, :class => 'elem' do |component|
52
+ component.use :label
53
+ component.use :input, :wrap_with => { :tag => :div, :class => 'input' }
54
+ end
55
+ end
56
+ end
57
+
58
+ def custom_wrapper_with_wrapped_label
59
+ SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
60
+ b.wrapper :tag => :div, :class => 'elem' do |component|
61
+ component.use :label, :wrap_with => { :tag => :div, :class => 'label' }
62
+ component.use :input
63
+ end
64
+ end
65
+ end
66
+
67
+ def custom_wrapper_without_top_level
68
+ SimpleForm.build :tag => false, :class => 'custom_wrapper_without_top_level' do |b|
69
+ b.use :label_input
70
+ b.use :hint, :wrap_with => { :tag => :span, :class => :hint }
71
+ b.use :error, :wrap_with => { :tag => :span, :class => :error }
72
+ end
73
+ end
74
+
75
+ def custom_wrapper_without_class
76
+ SimpleForm.build :tag => :div, :wrapper_html => { :id => 'custom_wrapper_without_class' } do |b|
77
+ b.use :label_input
78
+ end
79
+ end
80
+
81
+ def custom_wrapper_with_label_html_option
82
+ SimpleForm.build :tag => :div, :class => "custom_wrapper", :label_html => { :class => 'extra-label-class' } do |b|
83
+ b.use :label_input
84
+ end
85
+ end
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
+
93
+ def custom_form_for(object, *args, &block)
94
+ simple_form_for(object, *(args << { :builder => CustomFormBuilder }), &block)
95
+ end
96
+
97
+ def custom_mapping_form_for(object, *args, &block)
98
+ simple_form_for(object, *(args << { :builder => CustomMapTypeFormBuilder }), &block)
99
+ end
100
+
101
+ def with_concat_form_for(*args, &block)
102
+ concat simple_form_for(*args, &(block || proc {}))
103
+ end
104
+
105
+ def with_concat_fields_for(*args, &block)
106
+ concat simple_fields_for(*args, &block)
107
+ end
108
+
109
+ def with_concat_custom_form_for(*args, &block)
110
+ concat custom_form_for(*args, &block)
111
+ end
112
+
113
+ def with_concat_custom_mapping_form_for(*args, &block)
114
+ concat custom_mapping_form_for(*args, &block)
115
+ end
116
+
117
+ def with_form_for(object, *args, &block)
118
+ with_concat_form_for(object) do |f|
119
+ f.input(*args, &block)
120
+ end
121
+ end
122
+
123
+ def with_input_for(object, attribute_name, type, options={})
124
+ with_concat_form_for(object) do |f|
125
+ f.input(attribute_name, options.merge(:as => type))
126
+ end
127
+ end
128
+ end
129
+
130
+ class CustomFormBuilder < SimpleForm::FormBuilder
131
+ def input(attribute_name, *args, &block)
132
+ super(attribute_name, *(args << { :input_html => { :class => 'custom' } }), &block)
133
+ end
134
+ end
135
+
136
+ class CustomMapTypeFormBuilder < SimpleForm::FormBuilder
137
+ map_type :custom_type, :to => SimpleForm::Inputs::StringInput
138
+ end
@@ -0,0 +1,24 @@
1
+ class MockController
2
+ attr_writer :action_name
3
+
4
+ def _routes
5
+ self
6
+ end
7
+
8
+ def action_name
9
+ defined?(@action_name) ? @action_name : "edit"
10
+ end
11
+
12
+ def url_for(*args)
13
+ "http://example.com"
14
+ end
15
+
16
+ def url_helpers
17
+ self
18
+ end
19
+
20
+ def hash_for_user_path(*args); end
21
+ def hash_for_validating_user_path(*args); end
22
+ def hash_for_other_validating_user_path(*args); end
23
+ def hash_for_users_path(*args); end
24
+ end
@@ -0,0 +1,216 @@
1
+ Association = Struct.new(:klass, :name, :macro, :options)
2
+
3
+ class Column < Struct.new(:name, :type, :limit)
4
+ # Returns +true+ if the column is either of type integer, float or decimal.
5
+ def number?
6
+ type == :integer || type == :float || type == :decimal
7
+ end
8
+ end
9
+
10
+ class Company < Struct.new(:id, :name)
11
+ extend ActiveModel::Naming
12
+ include ActiveModel::Conversion
13
+
14
+ def self.all(options={})
15
+ all = (1..3).map{|i| Company.new(i, "Company #{i}")}
16
+ return [all.first] if options[:conditions].present?
17
+ return [all.last] if options[:order].present?
18
+ return all[0..1] if options[:include].present?
19
+ return all[1..2] if options[:joins].present?
20
+ all
21
+ end
22
+
23
+ def self.merge_conditions(a, b)
24
+ (a || {}).merge(b || {})
25
+ end
26
+
27
+ def persisted?
28
+ true
29
+ end
30
+ end
31
+
32
+ class Tag < Company
33
+ def self.all(options={})
34
+ (1..3).map{|i| Tag.new(i, "Tag #{i}")}
35
+ end
36
+ end
37
+
38
+ class TagGroup < Struct.new(:id, :name, :tags)
39
+ end
40
+
41
+ class User
42
+ extend ActiveModel::Naming
43
+ include ActiveModel::Conversion
44
+
45
+ attr_accessor :id, :name, :company, :company_id, :time_zone, :active, :age,
46
+ :description, :created_at, :updated_at, :credit_limit, :password, :url,
47
+ :delivery_time, :born_at, :special_company_id, :country, :tags, :tag_ids,
48
+ :avatar, :home_picture, :email, :status, :residence_country, :phone_number,
49
+ :post_count, :lock_version, :amount, :attempts, :action, :credit_card, :gender
50
+
51
+ def initialize(options={})
52
+ @new_record = false
53
+ options.each do |key, value|
54
+ send("#{key}=", value)
55
+ end if options
56
+ end
57
+
58
+ def new_record!
59
+ @new_record = true
60
+ end
61
+
62
+ def persisted?
63
+ !@new_record
64
+ end
65
+
66
+ def company_attributes=(*)
67
+ end
68
+
69
+ def tags_attributes=(*)
70
+ end
71
+
72
+ def column_for_attribute(attribute)
73
+ column_type, limit = case attribute.to_sym
74
+ when :name, :status, :password then [:string, 100]
75
+ when :description then [:text, 200]
76
+ when :age then :integer
77
+ when :credit_limit then [:decimal, 15]
78
+ when :active then :boolean
79
+ when :born_at then :date
80
+ when :delivery_time then :time
81
+ when :created_at then :datetime
82
+ when :updated_at then :timestamp
83
+ when :lock_version then :integer
84
+ when :home_picture then :string
85
+ when :amount then :integer
86
+ when :attempts then :integer
87
+ when :action then :string
88
+ when :credit_card then :string
89
+ end
90
+ Column.new(attribute, column_type, limit)
91
+ end
92
+
93
+ def self.human_attribute_name(attribute)
94
+ case attribute
95
+ when 'name'
96
+ 'Super User Name!'
97
+ when 'description'
98
+ 'User Description!'
99
+ when 'company'
100
+ 'Company Human Name!'
101
+ else
102
+ attribute.humanize
103
+ end
104
+ end
105
+
106
+ def self.reflect_on_association(association)
107
+ case association
108
+ when :company
109
+ Association.new(Company, association, :belongs_to, {})
110
+ when :tags
111
+ Association.new(Tag, association, :has_many, {})
112
+ when :first_company
113
+ Association.new(Company, association, :has_one, {})
114
+ when :special_company
115
+ Association.new(Company, association, :belongs_to, { :conditions => { :id => 1 } })
116
+ end
117
+ end
118
+
119
+ def errors
120
+ @errors ||= begin
121
+ hash = Hash.new { |h,k| h[k] = [] }
122
+ hash.merge!(
123
+ :name => ["can't be blank"],
124
+ :description => ["must be longer than 15 characters"],
125
+ :age => ["is not a number", "must be greater than 18"],
126
+ :company => ["company must be present"],
127
+ :company_id => ["must be valid"]
128
+ )
129
+ end
130
+ end
131
+
132
+ def self.readonly_attributes
133
+ ["credit_card"]
134
+ end
135
+ end
136
+
137
+ class ValidatingUser < User
138
+ include ActiveModel::Validations
139
+ validates :name, :presence => true
140
+ validates :company, :presence => true
141
+ validates :age, :presence => true, :if => Proc.new { |user| user.name }
142
+ validates :amount, :presence => true, :unless => Proc.new { |user| user.age }
143
+
144
+ validates :action, :presence => true, :on => :create
145
+ validates :credit_limit, :presence => true, :on => :save
146
+ validates :phone_number, :presence => true, :on => :update
147
+
148
+ validates_numericality_of :age,
149
+ :greater_than_or_equal_to => 18,
150
+ :less_than_or_equal_to => 99,
151
+ :only_integer => true
152
+ validates_numericality_of :amount,
153
+ :greater_than => :min_amount,
154
+ :less_than => :max_amount,
155
+ :only_integer => true
156
+ validates_numericality_of :attempts,
157
+ :greater_than_or_equal_to => :min_attempts,
158
+ :less_than_or_equal_to => :max_attempts,
159
+ :only_integer => true
160
+ validates_length_of :name, :maximum => 25
161
+ validates_length_of :description, :maximum => 50
162
+ validates_length_of :action, :maximum => 10, :tokenizer => lambda { |str| str.scan(/\w+/) }
163
+ validates_length_of :home_picture, :is => 12
164
+
165
+ def min_amount
166
+ 10
167
+ end
168
+
169
+ def max_amount
170
+ 100
171
+ end
172
+
173
+ def min_attempts
174
+ 1
175
+ end
176
+
177
+ def max_attempts
178
+ 100
179
+ end
180
+ end
181
+
182
+ class OtherValidatingUser < User
183
+ include ActiveModel::Validations
184
+ validates_numericality_of :age,
185
+ :greater_than => 17,
186
+ :less_than => 100,
187
+ :only_integer => true
188
+ validates_numericality_of :amount,
189
+ :greater_than => Proc.new { |user| user.age },
190
+ :less_than => Proc.new { |user| user.age + 100},
191
+ :only_integer => true
192
+ validates_numericality_of :attempts,
193
+ :greater_than_or_equal_to => Proc.new { |user| user.age },
194
+ :less_than_or_equal_to => Proc.new { |user| user.age + 100},
195
+ :only_integer => true
196
+
197
+ validates_format_of :country, :with => /\w+/
198
+
199
+ # TODO: Remove this check when we drop Rails 3.0 support
200
+ if ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR >= 1
201
+ validates_format_of :name, :with => Proc.new { /\w+/ }
202
+ else
203
+ validates_format_of :name, :with => /\w+/
204
+ end
205
+ end
206
+
207
+ class HashBackedAuthor < Hash
208
+ extend ActiveModel::Naming
209
+ include ActiveModel::Conversion
210
+
211
+ def persisted?; false; end
212
+
213
+ def name
214
+ 'hash backed author'
215
+ end
216
+ end
@@ -0,0 +1,95 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'test/unit'
5
+ require 'mocha/setup'
6
+
7
+ require 'active_model'
8
+ require 'action_controller'
9
+ require 'action_view'
10
+ require 'action_view/template'
11
+
12
+ # Rails 3.0.4 is missing this "deprecation" require.
13
+ require 'active_support/core_ext/module/deprecation'
14
+ require 'action_view/test_case'
15
+
16
+ module Rails
17
+ def self.env
18
+ ActiveSupport::StringInquirer.new("test")
19
+ end
20
+ end
21
+
22
+ $:.unshift File.expand_path("../../lib", __FILE__)
23
+ require 'simple_form'
24
+
25
+ require "rails/generators/test_case"
26
+ require 'generators/simple_form/install_generator'
27
+
28
+ Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
29
+ require file unless file.end_with?('discovery_inputs.rb')
30
+ end
31
+ I18n.default_locale = :en
32
+
33
+ require 'country_select'
34
+
35
+ ActionDispatch::Assertions::NO_STRIP << "label"
36
+
37
+ class ActionView::TestCase
38
+ include MiscHelpers
39
+ include SimpleForm::ActionViewExtensions::FormHelper
40
+
41
+ setup :set_controller
42
+ setup :setup_new_user
43
+
44
+ def set_controller
45
+ @controller = MockController.new
46
+ end
47
+
48
+ def setup_new_user(options={})
49
+ @user = User.new({
50
+ :id => 1,
51
+ :name => 'New in SimpleForm!',
52
+ :description => 'Hello!',
53
+ :created_at => Time.now
54
+ }.merge(options))
55
+
56
+ @validating_user = ValidatingUser.new({
57
+ :id => 1,
58
+ :name => 'New in SimpleForm!',
59
+ :description => 'Hello!',
60
+ :home_picture => 'Home picture',
61
+ :created_at => Time.now,
62
+ :age => 19,
63
+ :amount => 15,
64
+ :attempts => 1,
65
+ :company => [1]
66
+ }.merge(options))
67
+
68
+ @other_validating_user = OtherValidatingUser.new({
69
+ :id => 1,
70
+ :name => 'New in SimpleForm!',
71
+ :description => 'Hello!',
72
+ :created_at => Time.now,
73
+ :age => 19,
74
+ :company => 1
75
+ }.merge(options))
76
+ end
77
+
78
+ def protect_against_forgery?
79
+ false
80
+ end
81
+
82
+ def user_path(*args)
83
+ '/users'
84
+ end
85
+
86
+ def company_user_path(*args)
87
+ '/company/users'
88
+ end
89
+
90
+ alias :users_path :user_path
91
+ alias :super_user_path :user_path
92
+ alias :validating_user_path :user_path
93
+ alias :validating_users_path :user_path
94
+ alias :other_validating_user_path :user_path
95
+ end