simple_form 3.0.4 → 3.1.0.rc1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -43
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +146 -71
  5. data/lib/generators/simple_form/install_generator.rb +2 -2
  6. data/lib/generators/simple_form/templates/README +3 -4
  7. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +19 -3
  8. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +83 -22
  9. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +1 -1
  10. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
  11. data/lib/simple_form.rb +38 -6
  12. data/lib/simple_form/action_view_extensions/form_helper.rb +1 -1
  13. data/lib/simple_form/components/errors.rb +27 -5
  14. data/lib/simple_form/components/hints.rb +2 -2
  15. data/lib/simple_form/components/html5.rb +1 -1
  16. data/lib/simple_form/components/label_input.rb +20 -2
  17. data/lib/simple_form/components/labels.rb +9 -5
  18. data/lib/simple_form/components/maxlength.rb +1 -1
  19. data/lib/simple_form/components/min_max.rb +1 -1
  20. data/lib/simple_form/components/pattern.rb +1 -1
  21. data/lib/simple_form/components/placeholders.rb +2 -2
  22. data/lib/simple_form/components/readonly.rb +1 -1
  23. data/lib/simple_form/form_builder.rb +92 -59
  24. data/lib/simple_form/helpers.rb +5 -5
  25. data/lib/simple_form/inputs/base.rb +34 -12
  26. data/lib/simple_form/inputs/block_input.rb +1 -1
  27. data/lib/simple_form/inputs/boolean_input.rb +23 -13
  28. data/lib/simple_form/inputs/collection_input.rb +32 -9
  29. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +6 -11
  30. data/lib/simple_form/inputs/collection_select_input.rb +4 -2
  31. data/lib/simple_form/inputs/date_time_input.rb +12 -2
  32. data/lib/simple_form/inputs/file_input.rb +4 -2
  33. data/lib/simple_form/inputs/grouped_collection_select_input.rb +15 -3
  34. data/lib/simple_form/inputs/hidden_input.rb +4 -2
  35. data/lib/simple_form/inputs/numeric_input.rb +5 -4
  36. data/lib/simple_form/inputs/password_input.rb +4 -2
  37. data/lib/simple_form/inputs/priority_input.rb +4 -2
  38. data/lib/simple_form/inputs/range_input.rb +1 -1
  39. data/lib/simple_form/inputs/string_input.rb +4 -2
  40. data/lib/simple_form/inputs/text_input.rb +4 -2
  41. data/lib/simple_form/railtie.rb +7 -0
  42. data/lib/simple_form/tags.rb +7 -0
  43. data/lib/simple_form/version.rb +1 -1
  44. data/lib/simple_form/wrappers.rb +1 -0
  45. data/lib/simple_form/wrappers/builder.rb +5 -5
  46. data/lib/simple_form/wrappers/leaf.rb +28 -0
  47. data/lib/simple_form/wrappers/many.rb +5 -6
  48. data/lib/simple_form/wrappers/root.rb +1 -1
  49. data/lib/simple_form/wrappers/single.rb +5 -3
  50. data/test/action_view_extensions/builder_test.rb +2 -2
  51. data/test/components/label_test.rb +1 -1
  52. data/test/form_builder/association_test.rb +17 -0
  53. data/test/form_builder/error_notification_test.rb +1 -1
  54. data/test/form_builder/error_test.rb +51 -32
  55. data/test/form_builder/general_test.rb +2 -2
  56. data/test/form_builder/input_field_test.rb +21 -37
  57. data/test/form_builder/label_test.rb +24 -1
  58. data/test/form_builder/wrapper_test.rb +67 -0
  59. data/test/generators/simple_form_generator_test.rb +2 -2
  60. data/test/inputs/boolean_input_test.rb +50 -2
  61. data/test/inputs/collection_check_boxes_input_test.rb +40 -11
  62. data/test/inputs/collection_radio_buttons_input_test.rb +76 -17
  63. data/test/inputs/collection_select_input_test.rb +108 -3
  64. data/test/inputs/datetime_input_test.rb +105 -38
  65. data/test/inputs/discovery_test.rb +12 -1
  66. data/test/inputs/grouped_collection_select_input_test.rb +36 -0
  67. data/test/inputs/string_input_test.rb +20 -0
  68. data/test/simple_form_test.rb +8 -0
  69. data/test/support/discovery_inputs.rb +12 -2
  70. data/test/support/misc_helpers.rb +46 -8
  71. data/test/support/models.rb +49 -24
  72. metadata +7 -7
@@ -1,18 +1,69 @@
1
1
  # encoding: UTF-8
2
2
  require 'test_helper'
3
3
 
4
- # Tests for all different kinds of inputs.
5
- class DateTimeInputTest < ActionView::TestCase
6
- # DateTime input
7
- test 'input should generate a datetime select by default for datetime attributes' do
4
+ # Tests for datetime, date and time inputs when HTML5 compatibility is enabled in the wrapper.
5
+ class DateTimeInputWithHtml5Test < ActionView::TestCase
6
+ test 'input should generate a datetime input for datetime attributes if HTML5 compatibility is explicitly enbled' do
7
+ with_input_for @user, :created_at, :datetime, html5: true
8
+
9
+ assert_select 'input[type="datetime"]'
10
+ end
11
+
12
+ test 'input should generate a datetime select for datetime attributes' do
8
13
  with_input_for @user, :created_at, :datetime
9
- 1.upto(5) do |i|
10
- assert_select "form select.datetime#user_created_at_#{i}i"
14
+
15
+ assert_select 'select.datetime'
16
+ end
17
+
18
+ test 'input should generate a date input for date attributes if HTML5 compatibility is explicitly enbled' do
19
+ with_input_for @user, :born_at, :date, html5: true
20
+
21
+ assert_select 'input[type="date"]'
22
+ end
23
+
24
+ test 'input should generate a date select for date attributes' do
25
+ with_input_for @user, :born_at, :date
26
+
27
+ assert_select 'select.date'
28
+ end
29
+
30
+ test 'input should generate a time input for time attributes if HTML5 compatibility is explicitly enbled' do
31
+ with_input_for @user, :delivery_time, :time, html5: true
32
+
33
+ assert_select 'input[type="time"]'
34
+ end
35
+
36
+ test 'input should generate a time select for time attributes' do
37
+ with_input_for @user, :delivery_time, :time
38
+
39
+ assert_select 'select.time'
40
+ end
41
+
42
+ test 'input should generate required html attribute' do
43
+ with_input_for @user, :delivery_time, :time, required: true, html5: true
44
+ assert_select 'input.required'
45
+ assert_select 'input[required]'
46
+ end
47
+
48
+ test 'input should have an aria-required html attribute' do
49
+ with_input_for @user, :delivery_time, :time, required: true, html5: true
50
+ assert_select 'input[aria-required=true]'
51
+ end
52
+ end
53
+
54
+ # Tests for datetime, date and time inputs when HTML5 compatibility is enabled in the wrapper.
55
+ class DateTimeInputWithoutHtml5Test < ActionView::TestCase
56
+ test 'input should generate a datetime select by default for datetime attributes' do
57
+ swap_wrapper do
58
+ with_input_for @user, :created_at, :datetime
59
+ 1.upto(5) do |i|
60
+ assert_select "form select.datetime#user_created_at_#{i}i"
61
+ end
11
62
  end
12
63
  end
13
64
 
14
65
  test 'input should be able to pass options to datetime select' do
15
- with_input_for @user, :created_at, :datetime,
66
+ with_input_for @user, :created_at, :datetime, html5: false,
16
67
  disabled: true, prompt: { year: 'ano', month: 'mês', day: 'dia' }
17
68
 
18
69
  assert_select 'select.datetime[disabled=disabled]'
@@ -21,16 +72,26 @@ class DateTimeInputTest < ActionView::TestCase
21
72
  assert_select 'select.datetime option', 'dia'
22
73
  end
23
74
 
75
+ test 'input should generate a datetime input for datetime attributes if HTML5 compatibility is explicitly enabled' do
76
+ swap_wrapper do
77
+ with_input_for @user, :created_at, :datetime, html5: true
78
+
79
+ assert_select 'input[type="datetime"]'
80
+ end
81
+ end
82
+
24
83
  test 'input should generate a date select for date attributes' do
25
- with_input_for @user, :born_at, :date
26
- assert_select 'select.date#user_born_at_1i'
27
- assert_select 'select.date#user_born_at_2i'
28
- assert_select 'select.date#user_born_at_3i'
29
- assert_no_select 'select.date#user_born_at_4i'
84
+ swap_wrapper do
85
+ with_input_for @user, :born_at, :date
86
+ assert_select 'select.date#user_born_at_1i'
87
+ assert_select 'select.date#user_born_at_2i'
88
+ assert_select 'select.date#user_born_at_3i'
89
+ assert_no_select 'select.date#user_born_at_4i'
90
+ end
30
91
  end
31
92
 
32
93
  test 'input should be able to pass options to date select' do
33
- with_input_for @user, :born_at, :date, as: :date,
94
+ with_input_for @user, :born_at, :date, as: :date, html5: false,
34
95
  disabled: true, prompt: { year: 'ano', month: 'mês', day: 'dia' }
35
96
 
36
97
  assert_select 'select.date[disabled=disabled]'
@@ -40,21 +101,31 @@ class DateTimeInputTest < ActionView::TestCase
40
101
  end
41
102
 
42
103
  test 'input should be able to pass :default to date select' do
43
- with_input_for @user, :born_at, :date, default: Date.today
104
+ with_input_for @user, :born_at, :date, default: Date.today, html5: false
44
105
  assert_select "select.date option[value=#{Date.today.year}][selected=selected]"
45
106
  end
46
107
 
108
+ test 'input should generate a date input for date attributes if HTML5 compatibility is explicitly enabled' do
109
+ swap_wrapper do
110
+ with_input_for @user, :born_at, :date, html5: true
111
+
112
+ assert_select 'input[type="date"]'
113
+ end
114
+ end
115
+
47
116
  test 'input should generate a time select for time attributes' do
48
- with_input_for @user, :delivery_time, :time
49
- assert_select 'input[type=hidden]#user_delivery_time_1i'
50
- assert_select 'input[type=hidden]#user_delivery_time_2i'
51
- assert_select 'input[type=hidden]#user_delivery_time_3i'
52
- assert_select 'select.time#user_delivery_time_4i'
53
- assert_select 'select.time#user_delivery_time_5i'
117
+ swap_wrapper do
118
+ with_input_for @user, :delivery_time, :time
119
+ assert_select 'input[type=hidden]#user_delivery_time_1i'
120
+ assert_select 'input[type=hidden]#user_delivery_time_2i'
121
+ assert_select 'input[type=hidden]#user_delivery_time_3i'
122
+ assert_select 'select.time#user_delivery_time_4i'
123
+ assert_select 'select.time#user_delivery_time_5i'
124
+ end
54
125
  end
55
126
 
56
127
  test 'input should be able to pass options to time select' do
57
- with_input_for @user, :delivery_time, :time, required: true,
128
+ with_input_for @user, :delivery_time, :time, required: true, html5: false,
58
129
  disabled: true, prompt: { hour: 'hora', minute: 'minuto' }
59
130
 
60
131
  assert_select 'select.time[disabled=disabled]'
@@ -62,44 +133,40 @@ class DateTimeInputTest < ActionView::TestCase
62
133
  assert_select 'select.time option', 'minuto'
63
134
  end
64
135
 
136
+ test 'input should generate a time input for time attributes if HTML5 compatibility is explicitly enabled' do
137
+ swap_wrapper do
138
+ with_input_for @user, :delivery_time, :time, html5: true
139
+
140
+ assert_select 'input[type="time"]'
141
+ end
142
+ end
143
+
65
144
  test 'label should use i18n to get target for date input type' do
66
145
  store_translations(:en, date: { order: ['month', 'day', 'year'] }) do
67
- with_input_for :project, :created_at, :date
146
+ with_input_for :project, :created_at, :date, html5: false
68
147
  assert_select 'label[for=project_created_at_2i]'
69
148
  end
70
149
  end
71
150
 
72
151
  test 'label should use i18n to get target for datetime input type' do
73
152
  store_translations(:en, date: { order: ['month', 'day', 'year'] }) do
74
- with_input_for :project, :created_at, :datetime
153
+ with_input_for :project, :created_at, :datetime, html5: false
75
154
  assert_select 'label[for=project_created_at_2i]'
76
155
  end
77
156
  end
78
157
 
79
158
  test 'label should use order to get target when date input type' do
80
- with_input_for :project, :created_at, :date, order: ['month', 'year', 'day']
159
+ with_input_for :project, :created_at, :date, order: ['month', 'year', 'day'], html5: false
81
160
  assert_select 'label[for=project_created_at_2i]'
82
161
  end
83
162
 
84
163
  test 'label should use order to get target when datetime input type' do
85
- with_input_for :project, :created_at, :datetime, order: ['month', 'year', 'day']
164
+ with_input_for :project, :created_at, :datetime, order: ['month', 'year', 'day'], html5: false
86
165
  assert_select 'label[for=project_created_at_2i]'
87
166
  end
88
167
 
89
168
  test 'label should point to first option when time input type' do
90
- with_input_for :project, :created_at, :time
169
+ with_input_for :project, :created_at, :time, html5: false
91
170
  assert_select 'label[for=project_created_at_4i]'
92
171
  end
93
-
94
- test 'date time input should generate required html attribute' do
95
- with_input_for @user, :delivery_time, :time, required: true
96
- assert_select 'select.required'
97
- assert_select 'select[required]'
98
- end
99
-
100
- test 'date time input has an aria-required html attribute' do
101
- with_input_for @user, :delivery_time, :time, required: true
102
- assert_select 'select.required'
103
- assert_select 'select[aria-required=true]'
104
- end
105
172
  end
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class DiscoveryTest < ActionView::TestCase
4
4
  # Setup new inputs and remove them after the test.
5
- def discovery(value=false)
5
+ def discovery(value = false)
6
6
  swap SimpleForm, cache_discovery: value do
7
7
  begin
8
8
  load "support/discovery_inputs.rb"
@@ -12,6 +12,7 @@ class DiscoveryTest < ActionView::TestCase
12
12
  Object.send :remove_const, :StringInput
13
13
  Object.send :remove_const, :NumericInput
14
14
  Object.send :remove_const, :CustomizedInput
15
+ Object.send :remove_const, :DeprecatedInput
15
16
  Object.send :remove_const, :CollectionSelectInput
16
17
  end
17
18
  end
@@ -66,4 +67,14 @@ class DiscoveryTest < ActionView::TestCase
66
67
  assert_select 'form select#user_active.select.chosen'
67
68
  end
68
69
  end
70
+
71
+ test 'inputs method without wrapper_options are deprecated' do
72
+ discovery do
73
+ assert_deprecated do
74
+ with_form_for @user, :name, as: :deprecated
75
+ end
76
+
77
+ assert_select 'form section input#user_name.string'
78
+ end
79
+ end
69
80
  end
@@ -79,6 +79,42 @@ class GroupedCollectionSelectInputTest < ActionView::TestCase
79
79
  end
80
80
  end
81
81
 
82
+ test 'grouped collection finds default label methods on the group objects' do
83
+ option_list = ['Jose', 'Carlos']
84
+
85
+ GroupedClass = Struct.new(:to_label, :options)
86
+ group = GroupedClass.new("Authors", option_list)
87
+
88
+ with_input_for @user, :tag_ids, :grouped_select,
89
+ collection: [group],
90
+ group_method: :options
91
+
92
+ assert_select 'select.grouped_select#user_tag_ids' do
93
+ assert_select 'optgroup[label=Authors]' do
94
+ assert_select 'option', 'Jose'
95
+ assert_select 'option', 'Carlos'
96
+ end
97
+ end
98
+ end
99
+
100
+ test 'grouped collections finds the default label method from the first non-empty object' do
101
+ Agent = Struct.new(:id, :name)
102
+ agents = [["First", []], ["Second", [Agent.new(7, 'Bond'), Agent.new(47, 'Hitman')]]]
103
+
104
+ with_input_for @user, :tag_ids, :grouped_select,
105
+ collection: agents,
106
+ group_label_method: :first,
107
+ group_method: :last,
108
+ include_blank: false
109
+
110
+ assert_select 'select.grouped_select#user_tag_ids' do
111
+ assert_select 'optgroup[label=Second]' do
112
+ assert_select 'option[value=7]', 'Bond'
113
+ assert_select 'option[value=47]', 'Hitman'
114
+ end
115
+ end
116
+ end
117
+
82
118
  test 'grouped collection accepts label and value methods options' do
83
119
  with_input_for @user, :tag_ids, :grouped_select,
84
120
  collection: { 'Authors' => ['Jose', 'Carlos'] },
@@ -104,6 +104,26 @@ class StringInputTest < ActionView::TestCase
104
104
  end
105
105
  end
106
106
 
107
+ test 'input should use custom i18n scope to translate placeholder text' do
108
+ store_translations(:en, my_scope: { placeholders: { user: {
109
+ name: 'Name goes here'
110
+ } } }) do
111
+ swap SimpleForm, i18n_scope: :my_scope do
112
+ with_input_for @user, :name, :string
113
+ assert_select 'input.string[placeholder=Name goes here]'
114
+ end
115
+ end
116
+ end
117
+
118
+ test 'input should translate a key prefixed with _html and return the html markup' do
119
+ store_translations(:en, simple_form: { labels: { user: {
120
+ name_html: '<b>Name</b>'
121
+ } } }) do
122
+ with_input_for @user, :name, :string
123
+ assert_select 'label b', 'Name'
124
+ end
125
+ end
126
+
107
127
  [:email, :url, :search, :tel].each do |type|
108
128
  test "input should allow type #{type}" do
109
129
  with_input_for @user, :name, type
@@ -6,4 +6,12 @@ class SimpleFormTest < ActiveSupport::TestCase
6
6
  assert_equal SimpleForm, config
7
7
  end
8
8
  end
9
+
10
+ test 'setup block configure Simple Form' do
11
+ SimpleForm.setup do |config|
12
+ assert_equal SimpleForm, config
13
+ end
14
+
15
+ assert_equal true, SimpleForm.configured?
16
+ end
9
17
  end
@@ -1,16 +1,26 @@
1
1
  class StringInput < SimpleForm::Inputs::StringInput
2
- def input
2
+ def input(wrapper_options = nil)
3
3
  "<section>#{super}</section>".html_safe
4
4
  end
5
5
  end
6
6
 
7
7
  class NumericInput < SimpleForm::Inputs::NumericInput
8
- def input
8
+ def input(wrapper_options = nil)
9
9
  "<section>#{super}</section>".html_safe
10
10
  end
11
11
  end
12
12
 
13
13
  class CustomizedInput < SimpleForm::Inputs::StringInput
14
+ def input(wrapper_options = nil)
15
+ "<section>#{super}</section>".html_safe
16
+ end
17
+
18
+ def input_method
19
+ :text_field
20
+ end
21
+ end
22
+
23
+ class DeprecatedInput < SimpleForm::Inputs::StringInput
14
24
  def input
15
25
  "<section>#{super}</section>".html_safe
16
26
  end
@@ -46,12 +46,12 @@ module MiscHelpers
46
46
  end
47
47
  end
48
48
 
49
- def swap_wrapper(name=:default, wrapper=self.custom_wrapper)
50
- old = SimpleForm.wrappers[name]
51
- SimpleForm.wrappers[name] = wrapper
49
+ def swap_wrapper(name = :default, wrapper = self.custom_wrapper)
50
+ old = SimpleForm.wrappers[name.to_s]
51
+ SimpleForm.wrappers[name.to_s] = wrapper
52
52
  yield
53
53
  ensure
54
- SimpleForm.wrappers[name] = old
54
+ SimpleForm.wrappers[name.to_s] = old
55
55
  end
56
56
 
57
57
  def custom_wrapper
@@ -68,6 +68,32 @@ module MiscHelpers
68
68
  end
69
69
  end
70
70
 
71
+ def custom_wrapper_with_input_class
72
+ SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
73
+ b.use :label
74
+ b.use :input, class: 'inline-class'
75
+ end
76
+ end
77
+
78
+ def custom_wrapper_with_label_class
79
+ SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
80
+ b.use :label, class: 'inline-class'
81
+ b.use :input
82
+ end
83
+ end
84
+
85
+ def custom_wrapper_with_input_attributes
86
+ SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
87
+ b.use :input, data: { modal: true }
88
+ end
89
+ end
90
+
91
+ def custom_wrapper_with_label_input_class
92
+ SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
93
+ b.use :label_input, class: 'inline-class'
94
+ end
95
+ end
96
+
71
97
  def custom_wrapper_with_wrapped_input
72
98
  SimpleForm.build tag: :div, class: "custom_wrapper" do |b|
73
99
  b.wrapper tag: :div, class: 'elem' do |component|
@@ -112,9 +138,21 @@ module MiscHelpers
112
138
  end
113
139
  end
114
140
 
115
- def custom_wrapper_with_html5_components
116
- SimpleForm.build tag: :span, class: 'custom_wrapper' do |b|
117
- b.use :label_text
141
+ def custom_wrapper_with_additional_attributes
142
+ SimpleForm.build tag: :div, class: 'custom_wrapper', html: { data: { wrapper: :test }, title: 'some title' } do |b|
143
+ b.use :label_input
144
+ end
145
+ end
146
+
147
+ def custom_wrapper_with_full_error
148
+ SimpleForm.build tag: :div, class: 'custom_wrapper' do |b|
149
+ b.use :full_error, wrap_with: { tag: :span, class: :error }
150
+ end
151
+ end
152
+
153
+ def custom_wrapper_with_label_text
154
+ SimpleForm.build :label_text => proc { |label, required| "**#{label}**" } do |b|
155
+ b.use :label_input
118
156
  end
119
157
  end
120
158
 
@@ -148,7 +186,7 @@ module MiscHelpers
148
186
  end
149
187
  end
150
188
 
151
- def with_input_for(object, attribute_name, type, options={})
189
+ def with_input_for(object, attribute_name, type, options = {})
152
190
  with_concat_form_for(object) do |f|
153
191
  f.input(attribute_name, options.merge(as: type))
154
192
  end
@@ -1,4 +1,4 @@
1
- Association = Struct.new(:klass, :name, :macro, :options)
1
+ Association = Struct.new(:klass, :name, :macro, :scope, :options)
2
2
 
3
3
  Column = Struct.new(:name, :type, :limit) do
4
4
  # Returns +true+ if the column is either of type integer, float or decimal.
@@ -7,16 +7,36 @@ Column = Struct.new(:name, :type, :limit) do
7
7
  end
8
8
  end
9
9
 
10
- Relation = Struct.new(:all) do
10
+ Relation = Struct.new(:records) do
11
+ delegate :each, to: :records
12
+
11
13
  def where(conditions = nil)
12
- self.class.new conditions ? all.first : all
14
+ self.class.new conditions ? records.first : records
13
15
  end
14
16
 
15
17
  def order(conditions = nil)
16
- self.class.new conditions ? all.last : all
18
+ self.class.new conditions ? records.last : records
17
19
  end
18
20
 
19
- alias_method :to_a, :all
21
+ alias_method :to_a, :records
22
+ alias_method :to_ary, :records
23
+ end
24
+
25
+ Picture = Struct.new(:id, :name) do
26
+ extend ActiveModel::Naming
27
+ include ActiveModel::Conversion
28
+
29
+ def self.where(conditions = nil)
30
+ if conditions.is_a?(Hash) && conditions[:name]
31
+ all.to_a.last
32
+ else
33
+ all
34
+ end
35
+ end
36
+
37
+ def self.all
38
+ Relation.new((1..3).map { |i| new(i, "#{name} #{i}") })
39
+ end
20
40
  end
21
41
 
22
42
  Company = Struct.new(:id, :name) do
@@ -28,11 +48,11 @@ Company = Struct.new(:id, :name) do
28
48
  end
29
49
 
30
50
  def self._relation
31
- Relation.new(all)
51
+ all
32
52
  end
33
53
 
34
54
  def self.all
35
- (1..3).map { |i| new(i, "#{name} #{i}") }
55
+ Relation.new((1..3).map { |i| new(i, "#{name} #{i}") })
36
56
  end
37
57
 
38
58
  def persisted?
@@ -53,7 +73,8 @@ class User
53
73
  :delivery_time, :born_at, :special_company_id, :country, :tags, :tag_ids,
54
74
  :avatar, :home_picture, :email, :status, :residence_country, :phone_number,
55
75
  :post_count, :lock_version, :amount, :attempts, :action, :credit_card, :gender,
56
- :extra_special_company_id
76
+ :extra_special_company_id, :pictures, :picture_ids, :special_pictures,
77
+ :special_picture_ids
57
78
 
58
79
  def self.build(extra_attributes = {})
59
80
  attributes = {
@@ -66,7 +87,7 @@ class User
66
87
  new attributes
67
88
  end
68
89
 
69
- def initialize(options={})
90
+ def initialize(options = {})
70
91
  @new_record = false
71
92
  options.each do |key, value|
72
93
  send("#{key}=", value)
@@ -108,7 +129,7 @@ class User
108
129
  Column.new(attribute, column_type, limit)
109
130
  end
110
131
 
111
- def self.human_attribute_name(attribute)
132
+ def self.human_attribute_name(attribute, options = {})
112
133
  case attribute
113
134
  when 'name'
114
135
  'Super User Name!'
@@ -117,35 +138,39 @@ class User
117
138
  when 'company'
118
139
  'Company Human Name!'
119
140
  else
120
- attribute.humanize
141
+ attribute.to_s.humanize
121
142
  end
122
143
  end
123
144
 
124
145
  def self.reflect_on_association(association)
125
146
  case association
126
147
  when :company
127
- Association.new(Company, association, :belongs_to, {})
148
+ Association.new(Company, association, :belongs_to, nil, {})
128
149
  when :tags
129
- Association.new(Tag, association, :has_many, {})
150
+ Association.new(Tag, association, :has_many, nil, {})
130
151
  when :first_company
131
- Association.new(Company, association, :has_one, {})
152
+ Association.new(Company, association, :has_one, nil, {})
132
153
  when :special_company
133
- Association.new(Company, association, :belongs_to, { conditions: { id: 1 } })
154
+ Association.new(Company, association, :belongs_to, nil, { conditions: { id: 1 } })
134
155
  when :extra_special_company
135
- Association.new(Company, association, :belongs_to, { conditions: proc { { id: 1 } } })
156
+ Association.new(Company, association, :belongs_to, nil, { conditions: proc { { id: self.id } } })
157
+ when :pictures
158
+ Association.new(Picture, association, :has_many, nil, {})
159
+ when :special_pictures
160
+ Association.new(Picture, association, :has_many, proc { where(name: self.name) }, {})
136
161
  end
137
162
  end
138
163
 
139
164
  def errors
140
165
  @errors ||= begin
141
- hash = Hash.new { |h,k| h[k] = [] }
142
- hash.merge!(
143
- name: ["can't be blank"],
144
- description: ["must be longer than 15 characters"],
145
- age: ["is not a number", "must be greater than 18"],
146
- company: ["company must be present"],
147
- company_id: ["must be valid"]
148
- )
166
+ errors = ActiveModel::Errors.new(self)
167
+ errors.add(:name, "can't be blank")
168
+ errors.add(:description, 'must be longer than 15 characters')
169
+ errors.add(:age, 'is not a number')
170
+ errors.add(:age, 'must be greater than 18')
171
+ errors.add(:company, 'company must be present')
172
+ errors.add(:company_id, 'must be valid')
173
+ errors
149
174
  end
150
175
  end
151
176