ehoch_simple_form 2.0.2.dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG.md +257 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +797 -0
  4. data/lib/generators/simple_form/USAGE +3 -0
  5. data/lib/generators/simple_form/install_generator.rb +32 -0
  6. data/lib/generators/simple_form/templates/README +12 -0
  7. data/lib/generators/simple_form/templates/_form.html.erb +13 -0
  8. data/lib/generators/simple_form/templates/_form.html.haml +10 -0
  9. data/lib/generators/simple_form/templates/_form.html.slim +10 -0
  10. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb.tt +181 -0
  11. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +26 -0
  12. data/lib/simple_form.rb +215 -0
  13. data/lib/simple_form/action_view_extensions/builder.rb +338 -0
  14. data/lib/simple_form/action_view_extensions/form_helper.rb +74 -0
  15. data/lib/simple_form/components.rb +20 -0
  16. data/lib/simple_form/components/errors.rb +35 -0
  17. data/lib/simple_form/components/hints.rb +18 -0
  18. data/lib/simple_form/components/html5.rb +26 -0
  19. data/lib/simple_form/components/label_input.rb +15 -0
  20. data/lib/simple_form/components/labels.rb +79 -0
  21. data/lib/simple_form/components/maxlength.rb +41 -0
  22. data/lib/simple_form/components/min_max.rb +50 -0
  23. data/lib/simple_form/components/pattern.rb +34 -0
  24. data/lib/simple_form/components/placeholders.rb +16 -0
  25. data/lib/simple_form/components/readonly.rb +22 -0
  26. data/lib/simple_form/core_ext/hash.rb +16 -0
  27. data/lib/simple_form/error_notification.rb +48 -0
  28. data/lib/simple_form/form_builder.rb +472 -0
  29. data/lib/simple_form/helpers.rb +12 -0
  30. data/lib/simple_form/helpers/autofocus.rb +11 -0
  31. data/lib/simple_form/helpers/disabled.rb +15 -0
  32. data/lib/simple_form/helpers/readonly.rb +15 -0
  33. data/lib/simple_form/helpers/required.rb +35 -0
  34. data/lib/simple_form/helpers/validators.rb +44 -0
  35. data/lib/simple_form/i18n_cache.rb +22 -0
  36. data/lib/simple_form/inputs.rb +21 -0
  37. data/lib/simple_form/inputs/base.rb +162 -0
  38. data/lib/simple_form/inputs/block_input.rb +14 -0
  39. data/lib/simple_form/inputs/boolean_input.rb +64 -0
  40. data/lib/simple_form/inputs/collection_check_boxes_input.rb +21 -0
  41. data/lib/simple_form/inputs/collection_input.rb +101 -0
  42. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +63 -0
  43. data/lib/simple_form/inputs/collection_select_input.rb +14 -0
  44. data/lib/simple_form/inputs/date_time_input.rb +28 -0
  45. data/lib/simple_form/inputs/file_input.rb +9 -0
  46. data/lib/simple_form/inputs/grouped_collection_select_input.rb +41 -0
  47. data/lib/simple_form/inputs/hidden_input.rb +17 -0
  48. data/lib/simple_form/inputs/numeric_input.rb +24 -0
  49. data/lib/simple_form/inputs/password_input.rb +12 -0
  50. data/lib/simple_form/inputs/priority_input.rb +24 -0
  51. data/lib/simple_form/inputs/range_input.rb +14 -0
  52. data/lib/simple_form/inputs/string_input.rb +23 -0
  53. data/lib/simple_form/inputs/text_input.rb +11 -0
  54. data/lib/simple_form/map_type.rb +16 -0
  55. data/lib/simple_form/version.rb +3 -0
  56. data/lib/simple_form/wrappers.rb +8 -0
  57. data/lib/simple_form/wrappers/builder.rb +103 -0
  58. data/lib/simple_form/wrappers/many.rb +69 -0
  59. data/lib/simple_form/wrappers/root.rb +34 -0
  60. data/lib/simple_form/wrappers/single.rb +18 -0
  61. data/test/action_view_extensions/builder_test.rb +577 -0
  62. data/test/action_view_extensions/form_helper_test.rb +104 -0
  63. data/test/components/label_test.rb +310 -0
  64. data/test/form_builder/association_test.rb +177 -0
  65. data/test/form_builder/button_test.rb +47 -0
  66. data/test/form_builder/error_notification_test.rb +79 -0
  67. data/test/form_builder/error_test.rb +121 -0
  68. data/test/form_builder/general_test.rb +356 -0
  69. data/test/form_builder/hint_test.rb +139 -0
  70. data/test/form_builder/input_field_test.rb +63 -0
  71. data/test/form_builder/label_test.rb +71 -0
  72. data/test/form_builder/wrapper_test.rb +149 -0
  73. data/test/generators/simple_form_generator_test.rb +32 -0
  74. data/test/inputs/boolean_input_test.rb +108 -0
  75. data/test/inputs/collection_check_boxes_input_test.rb +224 -0
  76. data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
  77. data/test/inputs/collection_select_input_test.rb +241 -0
  78. data/test/inputs/datetime_input_test.rb +99 -0
  79. data/test/inputs/disabled_test.rb +38 -0
  80. data/test/inputs/discovery_test.rb +61 -0
  81. data/test/inputs/file_input_test.rb +16 -0
  82. data/test/inputs/general_test.rb +69 -0
  83. data/test/inputs/grouped_collection_select_input_test.rb +118 -0
  84. data/test/inputs/hidden_input_test.rb +30 -0
  85. data/test/inputs/numeric_input_test.rb +173 -0
  86. data/test/inputs/priority_input_test.rb +43 -0
  87. data/test/inputs/readonly_test.rb +61 -0
  88. data/test/inputs/required_test.rb +113 -0
  89. data/test/inputs/string_input_test.rb +140 -0
  90. data/test/inputs/text_input_test.rb +24 -0
  91. data/test/simple_form_test.rb +9 -0
  92. data/test/support/discovery_inputs.rb +21 -0
  93. data/test/support/misc_helpers.rb +102 -0
  94. data/test/support/mock_controller.rb +24 -0
  95. data/test/support/models.rb +210 -0
  96. data/test/test_helper.rb +90 -0
  97. metadata +210 -0
@@ -0,0 +1,338 @@
1
+ module SimpleForm
2
+ module ActionViewExtensions
3
+ # Base builder to handle each instance of a collection of radio buttons / check boxes.
4
+ # Based on (at this time upcoming) Rails 4 collection builders.
5
+ class BuilderBase #:nodoc:
6
+ attr_reader :object, :text, :value
7
+
8
+ def initialize(form_builder, method_name, object, sanitized_attribute_name, text,
9
+ value, input_html_options)
10
+ @form_builder = form_builder
11
+ @method_name = method_name
12
+ @object = object
13
+ @sanitized_attribute_name = sanitized_attribute_name
14
+ @text = text
15
+ @value = value
16
+ @input_html_options = input_html_options
17
+ end
18
+
19
+ def label(label_html_options={}, &block)
20
+ @form_builder.label(@sanitized_attribute_name, @text, label_html_options, &block)
21
+ end
22
+ end
23
+
24
+ # Handles generating an instance of radio + label for collection_radio_buttons.
25
+ class RadioButtonBuilder < BuilderBase #:nodoc:
26
+ def radio_button(extra_html_options={})
27
+ html_options = extra_html_options.merge(@input_html_options)
28
+ @form_builder.radio_button(@method_name, @value, html_options)
29
+ end
30
+ end
31
+
32
+ # Handles generating an instance of check box + label for collection_check_boxes.
33
+ class CheckBoxBuilder < BuilderBase #:nodoc:
34
+ def check_box(extra_html_options={})
35
+ html_options = extra_html_options.merge(@input_html_options)
36
+ @form_builder.check_box(@method_name, html_options, @value, nil)
37
+ end
38
+ end
39
+
40
+ # A collection of methods required by simple_form but added to rails default form.
41
+ # This means that you can use such methods outside simple_form context.
42
+ module Builder
43
+ # Create a collection of radio inputs for the attribute. Basically this
44
+ # helper will create a radio input associated with a label for each
45
+ # text/value option in the collection, using value_method and text_method
46
+ # to convert these text/value. You can give a symbol or a proc to both
47
+ # value_method and text_method, that will be evaluated for each item in
48
+ # the collection.
49
+ #
50
+ # == Examples
51
+ #
52
+ # form_for @user do |f|
53
+ # f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
54
+ # end
55
+ #
56
+ # <input id="user_options_true" name="user[options]" type="radio" value="true" />
57
+ # <label class="collection_radio_buttons" for="user_options_true">Yes</label>
58
+ # <input id="user_options_false" name="user[options]" type="radio" value="false" />
59
+ # <label class="collection_radio_buttons" for="user_options_false">No</label>
60
+ #
61
+ # It is also possible to give a block that should generate the radio +
62
+ # label. To wrap the radio with the label, for instance:
63
+ #
64
+ # form_for @user do |f|
65
+ # f.collection_radio_buttons(
66
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
67
+ # ) do |b|
68
+ # b.label { b.radio_button + b.text }
69
+ # end
70
+ # end
71
+ #
72
+ # == Options
73
+ #
74
+ # Collection radio accepts some extra options:
75
+ #
76
+ # * checked => the value that should be checked initially.
77
+ #
78
+ # * disabled => the value or values that should be disabled. Accepts a single
79
+ # item or an array of items.
80
+ #
81
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
82
+ #
83
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
84
+ #
85
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
86
+ #
87
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
88
+ #
89
+ # * a block => to generate the label + radio or any other component.
90
+ #
91
+ def collection_radio_buttons(attribute, collection, value_method, text_method, options={}, html_options={})
92
+ rendered_collection = render_collection(
93
+ collection, value_method, text_method, options, html_options
94
+ ) do |item, value, text, default_html_options|
95
+ builder = instantiate_builder(RadioButtonBuilder, attribute, item, value, text, default_html_options)
96
+
97
+ if block_given?
98
+ yield builder
99
+ else
100
+ builder.radio_button + builder.label(:class => "collection_radio_buttons")
101
+ end
102
+ end
103
+
104
+ wrap_rendered_collection(rendered_collection, options)
105
+ end
106
+
107
+ # deprecated
108
+ def collection_radio(*args, &block)
109
+ SimpleForm.deprecation_warn "The `collection_radio` helper is deprecated, " \
110
+ "please use `collection_radio_buttons` instead."
111
+ collection_radio_buttons(*args, &block)
112
+ end
113
+
114
+ # Creates a collection of check boxes for each item in the collection,
115
+ # associated with a clickable label. Use value_method and text_method to
116
+ # convert items in the collection for use as text/value in check boxes.
117
+ # You can give a symbol or a proc to both value_method and text_method,
118
+ # that will be evaluated for each item in the collection.
119
+ #
120
+ # == Examples
121
+ #
122
+ # form_for @user do |f|
123
+ # f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
124
+ # end
125
+ #
126
+ # <input name="user[options][]" type="hidden" value="" />
127
+ # <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
128
+ # <label class="collection_check_boxes" for="user_options_true">Yes</label>
129
+ # <input name="user[options][]" type="hidden" value="" />
130
+ # <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
131
+ # <label class="collection_check_boxes" for="user_options_false">No</label>
132
+ #
133
+ # It is also possible to give a block that should generate the check box +
134
+ # label. To wrap the check box with the label, for instance:
135
+ #
136
+ # form_for @user do |f|
137
+ # f.collection_check_boxes(
138
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
139
+ # ) do |b|
140
+ # b.label { b.check_box + b.text }
141
+ # end
142
+ # end
143
+ #
144
+ # == Options
145
+ #
146
+ # Collection check box accepts some extra options:
147
+ #
148
+ # * checked => the value or values that should be checked initially. Accepts
149
+ # a single item or an array of items. It overrides existing associations.
150
+ #
151
+ # * disabled => the value or values that should be disabled. Accepts a single
152
+ # item or an array of items.
153
+ #
154
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
155
+ #
156
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
157
+ #
158
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
159
+ #
160
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
161
+ #
162
+ # * a block => to generate the label + check box or any other component.
163
+ #
164
+ def collection_check_boxes(attribute, collection, value_method, text_method, options={}, html_options={})
165
+ rendered_collection = render_collection(
166
+ collection, value_method, text_method, options, html_options
167
+ ) do |item, value, text, default_html_options|
168
+ default_html_options[:multiple] = true
169
+ builder = instantiate_builder(CheckBoxBuilder, attribute, item, value, text, default_html_options)
170
+
171
+ if block_given?
172
+ yield builder
173
+ else
174
+ builder.check_box + builder.label(:class => "collection_check_boxes")
175
+ end
176
+ end
177
+
178
+ # Append a hidden field to make sure something will be sent back to the
179
+ # server if all checkboxes are unchecked.
180
+ hidden = template.hidden_field_tag("#{object_name}[#{attribute}][]", "", :id => nil)
181
+
182
+ wrap_rendered_collection(rendered_collection + hidden, options)
183
+ end
184
+
185
+ # Wrapper for using SimpleForm inside a default rails form.
186
+ # Example:
187
+ #
188
+ # form_for @user do |f|
189
+ # f.simple_fields_for :posts do |posts_form|
190
+ # # Here you have all simple_form methods available
191
+ # posts_form.input :title
192
+ # end
193
+ # end
194
+ def simple_fields_for(*args, &block)
195
+ options = args.extract_options!
196
+ options[:wrapper] ||= self.options[:wrapper]
197
+
198
+ if self.class < ActionView::Helpers::FormBuilder
199
+ options[:builder] ||= self.class
200
+ else
201
+ options[:builder] ||= SimpleForm::FormBuilder
202
+ end
203
+ fields_for(*(args << options), &block)
204
+ end
205
+
206
+ private
207
+
208
+ def instantiate_builder(builder_class, attribute, item, value, text, html_options)
209
+ builder_class.new(self, attribute, item,
210
+ sanitize_attribute_name(attribute, value), text, value, html_options)
211
+ end
212
+
213
+ # Generate default options for collection helpers, such as :checked and
214
+ # :disabled.
215
+ def default_html_options_for_collection(item, value, options, html_options) #:nodoc:
216
+ html_options = html_options.dup
217
+
218
+ [:checked, :selected, :disabled].each do |option|
219
+ current_option = options[option]
220
+ next if current_option.nil?
221
+
222
+ accept = if current_option.respond_to?(:call)
223
+ current_option.call(item)
224
+ else
225
+ Array(current_option).include?(value)
226
+ end
227
+
228
+ if accept
229
+ html_options[option] = true
230
+ elsif option == :checked
231
+ html_options[option] = false
232
+ end
233
+ end
234
+
235
+ html_options
236
+ end
237
+
238
+ def sanitize_attribute_name(attribute, value) #:nodoc:
239
+ "#{attribute}_#{value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}"
240
+ end
241
+
242
+ def render_collection(collection, value_method, text_method, options={}, html_options={}) #:nodoc:
243
+ item_wrapper_tag = options.fetch(:item_wrapper_tag, :span)
244
+ item_wrapper_class = options[:item_wrapper_class]
245
+
246
+ collection.map do |item|
247
+ value = value_for_collection(item, value_method)
248
+ text = value_for_collection(item, text_method)
249
+ default_html_options = default_html_options_for_collection(item, value, options, html_options)
250
+
251
+ rendered_item = yield item, value, text, default_html_options
252
+
253
+ item_wrapper_tag ? @template.content_tag(item_wrapper_tag, rendered_item, :class => item_wrapper_class) : rendered_item
254
+ end.join.html_safe
255
+ end
256
+
257
+ def value_for_collection(item, value) #:nodoc:
258
+ value.respond_to?(:call) ? value.call(item) : item.send(value)
259
+ end
260
+
261
+ def wrap_rendered_collection(collection, options)
262
+ wrapper_tag = options[:collection_wrapper_tag]
263
+
264
+ if wrapper_tag
265
+ wrapper_class = options[:collection_wrapper_class]
266
+ @template.content_tag(wrapper_tag, collection, :class => wrapper_class)
267
+ else
268
+ collection
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ module ActionView::Helpers
276
+ class FormBuilder
277
+ include SimpleForm::ActionViewExtensions::Builder
278
+
279
+ # Override default Rails collection_select helper to handle lambdas/procs in
280
+ # text and value methods, so it works the same way as collection_radio_buttons
281
+ # and collection_check_boxes in SimpleForm. If none of text/value methods is a
282
+ # callable object, then it just delegates back to original collection select.
283
+ #
284
+ alias :original_collection_select :collection_select
285
+ def collection_select(attribute, collection, value_method, text_method, options={}, html_options={})
286
+ if value_method.respond_to?(:call) || text_method.respond_to?(:call)
287
+ collection = collection.map do |item|
288
+ value = value_for_collection(item, value_method)
289
+ text = value_for_collection(item, text_method)
290
+
291
+ default_html_options = default_html_options_for_collection(item, value, options, html_options)
292
+ disabled = value if default_html_options[:disabled]
293
+ selected = value if default_html_options[:selected]
294
+
295
+ [value, text, selected, disabled]
296
+ end
297
+
298
+ [:disabled, :selected].each do |option|
299
+ option_value = collection.map(&:pop).compact
300
+ options[option] = option_value if option_value.present?
301
+ end
302
+ value_method, text_method = :first, :last
303
+ end
304
+
305
+ original_collection_select(attribute, collection, value_method, text_method, options, html_options)
306
+ end
307
+ end
308
+
309
+ # Backport Rails fix to checkbox tag element, which does not generate the
310
+ # hidden input when given nil as unchecked value. This is to make SimpleForm
311
+ # collection check boxes helper to work fine with nested boolean style, when
312
+ # they are wrapped in labels. Without that, clicking in the label would
313
+ # actually change the hidden input, instead of the checkbox.
314
+ # FIXME: remove when support only Rails >= 3.2.2.
315
+ class InstanceTag
316
+ def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
317
+ options = options.stringify_keys
318
+ options["type"] = "checkbox"
319
+ options["value"] = checked_value
320
+ if options.has_key?("checked")
321
+ cv = options.delete "checked"
322
+ checked = cv == true || cv == "checked"
323
+ else
324
+ checked = self.class.check_box_checked?(value(object), checked_value)
325
+ end
326
+ options["checked"] = "checked" if checked
327
+ if options["multiple"]
328
+ add_default_name_and_id_for_value(checked_value, options)
329
+ options.delete("multiple")
330
+ else
331
+ add_default_name_and_id(options)
332
+ end
333
+ hidden = unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => unchecked_value, "disabled" => options["disabled"]) : "".html_safe
334
+ checkbox = tag("input", options)
335
+ hidden + checkbox
336
+ end
337
+ end
338
+ end
@@ -0,0 +1,74 @@
1
+ module SimpleForm
2
+ module ActionViewExtensions
3
+ # This module creates SimpleForm wrappers around default form_for and fields_for.
4
+ #
5
+ # Example:
6
+ #
7
+ # simple_form_for @user do |f|
8
+ # f.input :name, :hint => 'My hint'
9
+ # end
10
+ #
11
+ module FormHelper
12
+ # based on what is done in formtastic
13
+ # http://github.com/justinfrench/formtastic/blob/master/lib/formtastic.rb#L1706
14
+ @@default_field_error_proc = nil
15
+
16
+ # Override the default ActiveRecordHelper behaviour of wrapping the input.
17
+ # This gets taken care of semantically by adding an error class to the wrapper tag
18
+ # containing the input.
19
+ #
20
+ FIELD_ERROR_PROC = proc do |html_tag, instance_tag|
21
+ html_tag
22
+ end
23
+
24
+ def simple_form_for(record, options={}, &block)
25
+ options[:builder] ||= SimpleForm::FormBuilder
26
+ options[:html] ||= {}
27
+ unless options[:html].key?(:novalidate)
28
+ options[:html][:novalidate] = !SimpleForm.browser_validations
29
+ end
30
+ options[:html][:class] = [SimpleForm.form_class, simple_form_css_class(record, options)].compact.join(" ")
31
+
32
+ with_simple_form_field_error_proc do
33
+ form_for(record, options, &block)
34
+ end
35
+ end
36
+
37
+ def simple_fields_for(record_name, record_object = nil, options = {}, &block)
38
+ options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
39
+ options[:builder] ||= SimpleForm::FormBuilder
40
+
41
+ with_simple_form_field_error_proc do
42
+ fields_for(record_name, record_object, options, &block)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def with_simple_form_field_error_proc
49
+ @@default_field_error_proc = ::ActionView::Base.field_error_proc
50
+ ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
51
+ result = yield
52
+ ::ActionView::Base.field_error_proc = @@default_field_error_proc
53
+ result
54
+ end
55
+
56
+ def simple_form_css_class(record, options)
57
+ html_options = options[:html]
58
+ as = options[:as]
59
+
60
+ if html_options.key?(:class)
61
+ html_options[:class]
62
+ elsif record.is_a?(String) || record.is_a?(Symbol)
63
+ as || record
64
+ else
65
+ record = record.last if record.is_a?(Array)
66
+ action = record.respond_to?(:persisted?) && record.persisted? ? :edit : :new
67
+ as ? "#{action}_#{as}" : dom_class(record, action)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ ActionView::Base.send :include, SimpleForm::ActionViewExtensions::FormHelper
@@ -0,0 +1,20 @@
1
+ module SimpleForm
2
+ # Components are a special type of helpers that can work on their own.
3
+ # For example, by using a component, it will automatically change the
4
+ # output under given circumstances without user input. For example,
5
+ # the disabled helper always need a :disabled => true option given
6
+ # to the input in order to be enabled. On the other hand, things like
7
+ # hints can generate output automatically by doing I18n lookups.
8
+ module Components
9
+ autoload :Errors, 'simple_form/components/errors'
10
+ autoload :Hints, 'simple_form/components/hints'
11
+ autoload :HTML5, 'simple_form/components/html5'
12
+ autoload :LabelInput, 'simple_form/components/label_input'
13
+ autoload :Labels, 'simple_form/components/labels'
14
+ autoload :MinMax, 'simple_form/components/min_max'
15
+ autoload :Maxlength, 'simple_form/components/maxlength'
16
+ autoload :Pattern, 'simple_form/components/pattern'
17
+ autoload :Placeholders, 'simple_form/components/placeholders'
18
+ autoload :Readonly, 'simple_form/components/readonly'
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ module SimpleForm
2
+ module Components
3
+ module Errors
4
+ def error
5
+ error_text if has_errors?
6
+ end
7
+
8
+ def has_errors?
9
+ object && object.respond_to?(:errors) && errors.present?
10
+ end
11
+
12
+ protected
13
+
14
+ def error_text
15
+ "#{options[:error_prefix]} #{errors.send(error_method)}".lstrip.html_safe
16
+ end
17
+
18
+ def error_method
19
+ options[:error_method] || SimpleForm.error_method
20
+ end
21
+
22
+ def errors
23
+ @errors ||= (errors_on_attribute + errors_on_association).compact
24
+ end
25
+
26
+ def errors_on_attribute
27
+ object.errors[attribute_name]
28
+ end
29
+
30
+ def errors_on_association
31
+ reflection ? object.errors[reflection.name] : []
32
+ end
33
+ end
34
+ end
35
+ end