formtastic 3.1.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/test.yml +61 -0
  4. data/.gitignore +3 -2
  5. data/CHANGELOG.md +52 -0
  6. data/Gemfile.lock +105 -0
  7. data/MIT-LICENSE +1 -1
  8. data/{README.textile → README.md} +178 -167
  9. data/RELEASE_PROCESS +3 -1
  10. data/Rakefile +20 -1
  11. data/app/assets/stylesheets/formtastic.css +1 -1
  12. data/bin/appraisal +8 -0
  13. data/formtastic.gemspec +10 -16
  14. data/gemfiles/rails_5.2/Gemfile +5 -0
  15. data/gemfiles/rails_6.0/Gemfile +5 -0
  16. data/gemfiles/rails_6.1/Gemfile +5 -0
  17. data/gemfiles/rails_edge/Gemfile +13 -0
  18. data/lib/formtastic.rb +9 -11
  19. data/lib/formtastic/actions.rb +6 -3
  20. data/lib/formtastic/deprecation.rb +1 -38
  21. data/lib/formtastic/engine.rb +3 -1
  22. data/lib/formtastic/form_builder.rb +11 -24
  23. data/lib/formtastic/helpers.rb +1 -1
  24. data/lib/formtastic/helpers/action_helper.rb +1 -48
  25. data/lib/formtastic/helpers/enum.rb +13 -0
  26. data/lib/formtastic/helpers/errors_helper.rb +2 -2
  27. data/lib/formtastic/helpers/fieldset_wrapper.rb +13 -9
  28. data/lib/formtastic/helpers/form_helper.rb +1 -1
  29. data/lib/formtastic/helpers/input_helper.rb +23 -77
  30. data/lib/formtastic/helpers/inputs_helper.rb +27 -22
  31. data/lib/formtastic/i18n.rb +1 -1
  32. data/lib/formtastic/inputs.rb +32 -29
  33. data/lib/formtastic/inputs/base/choices.rb +1 -1
  34. data/lib/formtastic/inputs/base/collections.rb +43 -10
  35. data/lib/formtastic/inputs/base/database.rb +7 -2
  36. data/lib/formtastic/inputs/base/errors.rb +4 -4
  37. data/lib/formtastic/inputs/base/hints.rb +1 -1
  38. data/lib/formtastic/inputs/base/html.rb +7 -6
  39. data/lib/formtastic/inputs/base/naming.rb +4 -4
  40. data/lib/formtastic/inputs/base/options.rb +2 -3
  41. data/lib/formtastic/inputs/base/timeish.rb +5 -1
  42. data/lib/formtastic/inputs/base/validations.rb +38 -12
  43. data/lib/formtastic/inputs/check_boxes_input.rb +13 -5
  44. data/lib/formtastic/inputs/color_input.rb +0 -1
  45. data/lib/formtastic/inputs/country_input.rb +3 -1
  46. data/lib/formtastic/inputs/radio_input.rb +20 -0
  47. data/lib/formtastic/inputs/select_input.rb +29 -1
  48. data/lib/formtastic/inputs/time_zone_input.rb +16 -6
  49. data/lib/formtastic/localizer.rb +20 -22
  50. data/lib/formtastic/namespaced_class_finder.rb +1 -1
  51. data/lib/formtastic/version.rb +1 -1
  52. data/lib/generators/formtastic/form/form_generator.rb +1 -1
  53. data/lib/generators/formtastic/input/input_generator.rb +46 -0
  54. data/lib/generators/templates/formtastic.rb +14 -13
  55. data/lib/generators/templates/input.rb +19 -0
  56. data/sample/basic_inputs.html +1 -1
  57. data/script/integration-template.rb +74 -0
  58. data/script/integration.sh +19 -0
  59. data/spec/action_class_finder_spec.rb +1 -1
  60. data/spec/actions/button_action_spec.rb +8 -8
  61. data/spec/actions/generic_action_spec.rb +60 -60
  62. data/spec/actions/input_action_spec.rb +7 -7
  63. data/spec/actions/link_action_spec.rb +10 -10
  64. data/spec/builder/custom_builder_spec.rb +37 -21
  65. data/spec/builder/error_proc_spec.rb +4 -4
  66. data/spec/builder/semantic_fields_for_spec.rb +27 -27
  67. data/spec/fast_spec_helper.rb +12 -0
  68. data/spec/generators/formtastic/form/form_generator_spec.rb +25 -25
  69. data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
  70. data/spec/generators/formtastic/install/install_generator_spec.rb +9 -9
  71. data/spec/helpers/action_helper_spec.rb +328 -10
  72. data/spec/helpers/actions_helper_spec.rb +17 -17
  73. data/spec/helpers/form_helper_spec.rb +37 -37
  74. data/spec/helpers/input_helper_spec.rb +975 -2
  75. data/spec/helpers/inputs_helper_spec.rb +120 -105
  76. data/spec/helpers/reflection_helper_spec.rb +3 -3
  77. data/spec/helpers/semantic_errors_helper_spec.rb +22 -22
  78. data/spec/i18n_spec.rb +26 -26
  79. data/spec/input_class_finder_spec.rb +1 -1
  80. data/spec/inputs/base/collections_spec.rb +76 -0
  81. data/spec/inputs/base/validations_spec.rb +480 -0
  82. data/spec/inputs/boolean_input_spec.rb +55 -55
  83. data/spec/inputs/check_boxes_input_spec.rb +155 -108
  84. data/spec/inputs/color_input_spec.rb +51 -63
  85. data/spec/inputs/country_input_spec.rb +20 -20
  86. data/spec/inputs/custom_input_spec.rb +2 -6
  87. data/spec/inputs/datalist_input_spec.rb +1 -1
  88. data/spec/inputs/date_picker_input_spec.rb +42 -42
  89. data/spec/inputs/date_select_input_spec.rb +51 -37
  90. data/spec/inputs/datetime_picker_input_spec.rb +46 -46
  91. data/spec/inputs/datetime_select_input_spec.rb +53 -37
  92. data/spec/inputs/email_input_spec.rb +5 -5
  93. data/spec/inputs/file_input_spec.rb +6 -6
  94. data/spec/inputs/hidden_input_spec.rb +18 -18
  95. data/spec/inputs/include_blank_spec.rb +8 -8
  96. data/spec/inputs/label_spec.rb +20 -20
  97. data/spec/inputs/number_input_spec.rb +112 -112
  98. data/spec/inputs/password_input_spec.rb +5 -5
  99. data/spec/inputs/phone_input_spec.rb +5 -5
  100. data/spec/inputs/placeholder_spec.rb +5 -5
  101. data/spec/inputs/radio_input_spec.rb +84 -58
  102. data/spec/inputs/range_input_spec.rb +66 -66
  103. data/spec/inputs/readonly_spec.rb +50 -0
  104. data/spec/inputs/search_input_spec.rb +5 -5
  105. data/spec/inputs/select_input_spec.rb +149 -93
  106. data/spec/inputs/string_input_spec.rb +23 -23
  107. data/spec/inputs/text_input_spec.rb +16 -16
  108. data/spec/inputs/time_picker_input_spec.rb +43 -43
  109. data/spec/inputs/time_select_input_spec.rb +67 -54
  110. data/spec/inputs/time_zone_input_spec.rb +54 -28
  111. data/spec/inputs/url_input_spec.rb +5 -5
  112. data/spec/inputs/with_options_spec.rb +7 -7
  113. data/spec/localizer_spec.rb +17 -17
  114. data/spec/namespaced_class_finder_spec.rb +2 -2
  115. data/spec/schema.rb +21 -0
  116. data/spec/spec_helper.rb +165 -253
  117. data/spec/support/custom_macros.rb +72 -75
  118. data/spec/support/shared_examples.rb +0 -1232
  119. data/spec/support/test_environment.rb +23 -9
  120. metadata +69 -176
  121. data/.travis.yml +0 -29
  122. data/Appraisals +0 -29
  123. data/CHANGELOG +0 -31
  124. data/DEPRECATIONS +0 -49
  125. data/gemfiles/rails_3.2.gemfile +0 -7
  126. data/gemfiles/rails_4.0.4.gemfile +0 -7
  127. data/gemfiles/rails_4.1.gemfile +0 -7
  128. data/gemfiles/rails_4.2.gemfile +0 -7
  129. data/gemfiles/rails_4.gemfile +0 -7
  130. data/gemfiles/rails_edge.gemfile +0 -10
  131. data/lib/formtastic/util.rb +0 -57
  132. data/spec/helpers/namespaced_action_helper_spec.rb +0 -43
  133. data/spec/helpers/namespaced_input_helper_spec.rb +0 -36
  134. data/spec/support/deferred_garbage_collection.rb +0 -21
  135. data/spec/util_spec.rb +0 -66
@@ -4,7 +4,12 @@ module Formtastic
4
4
  module Database
5
5
 
6
6
  def column
7
- object.column_for_attribute(method) if object.respond_to?(:column_for_attribute)
7
+ if object.respond_to?(:column_for_attribute)
8
+ # Remove deprecation wrapper & review after Rails 5.0 ships
9
+ ActiveSupport::Deprecation.silence do
10
+ object.column_for_attribute(method)
11
+ end
12
+ end
8
13
  end
9
14
 
10
15
  def column?
@@ -14,4 +19,4 @@ module Formtastic
14
19
  end
15
20
  end
16
21
  end
17
- end
22
+ end
@@ -9,21 +9,21 @@ module Formtastic
9
9
 
10
10
  def error_sentence_html
11
11
  error_class = builder.default_inline_error_class
12
- template.content_tag(:p, Formtastic::Util.html_safe(errors.to_sentence.html_safe), :class => error_class)
12
+ template.content_tag(:p, errors.to_sentence, :class => error_class)
13
13
  end
14
14
 
15
15
  def error_list_html
16
16
  error_class = builder.default_error_list_class
17
17
  list_elements = []
18
18
  errors.each do |error|
19
- list_elements << template.content_tag(:li, Formtastic::Util.html_safe(error.html_safe))
19
+ list_elements << template.content_tag(:li, error.html_safe)
20
20
  end
21
- template.content_tag(:ul, Formtastic::Util.html_safe(list_elements.join("\n")), :class => error_class)
21
+ template.content_tag(:ul, list_elements.join("\n").html_safe, :class => error_class)
22
22
  end
23
23
 
24
24
  def error_first_html
25
25
  error_class = builder.default_inline_error_class
26
- template.content_tag(:p, Formtastic::Util.html_safe(errors.first.untaint), :class => error_class)
26
+ template.content_tag(:p, errors.first.untaint.html_safe, :class => error_class)
27
27
  end
28
28
 
29
29
  def error_none_html
@@ -7,7 +7,7 @@ module Formtastic
7
7
  if hint?
8
8
  template.content_tag(
9
9
  :p,
10
- Formtastic::Util.html_safe(hint_text),
10
+ hint_text.html_safe,
11
11
  :class => builder.default_hint_class
12
12
  )
13
13
  end
@@ -2,7 +2,7 @@ module Formtastic
2
2
  module Inputs
3
3
  module Base
4
4
  module Html
5
-
5
+
6
6
  # Defines how the instance of an input should be rendered to a HTML string.
7
7
  #
8
8
  # @abstract Implement this method in your input class to describe how the input should render itself.
@@ -17,15 +17,16 @@ module Formtastic
17
17
  def to_html
18
18
  raise NotImplementedError
19
19
  end
20
-
20
+
21
21
  def input_html_options
22
- {
22
+ {
23
23
  :id => dom_id,
24
24
  :required => required_attribute?,
25
- :autofocus => autofocus?
25
+ :autofocus => autofocus?,
26
+ :readonly => readonly?
26
27
  }.merge(options[:input_html] || {})
27
28
  end
28
-
29
+
29
30
  def dom_id
30
31
  [
31
32
  builder.dom_id_namespace,
@@ -34,7 +35,7 @@ module Formtastic
34
35
  association_primary_key || sanitized_method_name
35
36
  ].reject { |x| x.blank? }.join('_')
36
37
  end
37
-
38
+
38
39
  def dom_index
39
40
  if builder.options.has_key?(:index)
40
41
  builder.options[:index]
@@ -4,9 +4,9 @@ module Formtastic
4
4
  module Naming
5
5
 
6
6
  def as
7
- self.class.name.split("::").last.underscore.gsub(/_input$/, '')
7
+ self.class.name.split("::")[-1].underscore.gsub(/_input$/, '')
8
8
  end
9
-
9
+
10
10
  def sanitized_object_name
11
11
  object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
12
12
  end
@@ -18,7 +18,7 @@ module Formtastic
18
18
  def attributized_method_name
19
19
  method.to_s.gsub(/_id$/, '').to_sym
20
20
  end
21
-
21
+
22
22
  def humanized_method_name
23
23
  if builder.label_str_method != :humanize
24
24
  # Special case where label_str_method should trump the human_attribute_name
@@ -39,4 +39,4 @@ module Formtastic
39
39
  end
40
40
  end
41
41
  end
42
- end
42
+ end
@@ -2,15 +2,14 @@ module Formtastic
2
2
  module Inputs
3
3
  module Base
4
4
  module Options
5
-
5
+
6
6
  def input_options
7
7
  options.except(*formtastic_options)
8
8
  end
9
-
9
+
10
10
  def formtastic_options
11
11
  [:priority_countries, :priority_zones, :member_label, :member_value, :collection, :required, :label, :as, :hint, :input_html, :value_as_class, :class]
12
12
  end
13
-
14
13
  end
15
14
  end
16
15
  end
@@ -85,6 +85,9 @@ module Formtastic
85
85
  # <%= f.input :publish_at, :as => :time_select, :include_blank => true %>
86
86
  # <%= f.input :publish_at, :as => :time_select, :include_blank => false %>
87
87
  #
88
+ # @example Provide a value for the field via selected
89
+ # <%= f.input :publish_at, :as => :datetime_select, :selected => DateTime.new(2018, 10, 4, 12, 00)
90
+ #
88
91
  # @todo Document i18n
89
92
  # @todo Check what other Rails options are supported (`start_year`, `end_year`, `use_month_numbers`, `use_short_month`, `add_month_numbers`, `prompt`), write tests for them, and otherwise support them
90
93
  # @todo Could we take the rendering from Rails' helpers and inject better HTML in and around it rather than re-inventing the whee?
@@ -157,6 +160,7 @@ module Formtastic
157
160
  end
158
161
 
159
162
  def value
163
+ return input_options[:selected] if options.key?(:selected)
160
164
  object.send(method) if object && object.respond_to?(method)
161
165
  end
162
166
 
@@ -238,4 +242,4 @@ module Formtastic
238
242
  end
239
243
  end
240
244
  end
241
- end
245
+ end
@@ -73,13 +73,11 @@ module Formtastic
73
73
  raise IndeterminableMinimumAttributeError if validation.options[:greater_than] && column? && [:float, :decimal].include?(column.type)
74
74
 
75
75
  if validation.options[:greater_than_or_equal_to]
76
- return (validation.options[:greater_than_or_equal_to].call(object)) if validation.options[:greater_than_or_equal_to].kind_of?(Proc)
77
- return (validation.options[:greater_than_or_equal_to])
76
+ return option_value(validation.options[:greater_than_or_equal_to], object)
78
77
  end
79
78
 
80
79
  if validation.options[:greater_than]
81
- return (validation.options[:greater_than].call(object) + 1) if validation.options[:greater_than].kind_of?(Proc)
82
- return (validation.options[:greater_than] + 1)
80
+ return option_value(validation.options[:greater_than], object) + 1
83
81
  end
84
82
  end
85
83
  end
@@ -94,13 +92,11 @@ module Formtastic
94
92
  raise IndeterminableMaximumAttributeError if validation.options[:less_than] && column? && [:float, :decimal].include?(column.type)
95
93
 
96
94
  if validation.options[:less_than_or_equal_to]
97
- return (validation.options[:less_than_or_equal_to].call(object)) if validation.options[:less_than_or_equal_to].kind_of?(Proc)
98
- return (validation.options[:less_than_or_equal_to])
95
+ return option_value(validation.options[:less_than_or_equal_to], object)
99
96
  end
100
97
 
101
98
  if validation.options[:less_than]
102
- return ((validation.options[:less_than].call(object)) - 1) if validation.options[:less_than].kind_of?(Proc)
103
- return (validation.options[:less_than] - 1)
99
+ return option_value(validation.options[:less_than], object) - 1
104
100
  end
105
101
  end
106
102
  end
@@ -136,9 +132,10 @@ module Formtastic
136
132
  return true if options[:required] == true
137
133
  return false if not_required_through_negated_validation?
138
134
  if validations?
139
- validations.select { |validator|
135
+ validations.any? { |validator|
140
136
  if validator.options.key?(:on)
141
- return false if (validator.options[:on] != :save) && ((object.new_record? && validator.options[:on] != :create) || (!object.new_record? && validator.options[:on] != :update))
137
+ validator_on = Array(validator.options[:on])
138
+ next false if (validator_on.exclude?(:save)) && ((object.new_record? && validator_on.exclude?(:create)) || (!object.new_record? && validator_on.exclude?(:update)))
142
139
  end
143
140
  case validator.kind
144
141
  when :presence
@@ -152,7 +149,7 @@ module Formtastic
152
149
  else
153
150
  false
154
151
  end
155
- }.any?
152
+ }
156
153
  else
157
154
  return responds_to_global_required? && !!builder.all_fields_required_by_default
158
155
  end
@@ -192,8 +189,37 @@ module Formtastic
192
189
  validation_limit || column_limit
193
190
  end
194
191
 
192
+ def readonly?
193
+ readonly_from_options? || readonly_attribute?
194
+ end
195
+
196
+ def readonly_attribute?
197
+ object_class = self.object.class
198
+ object_class.respond_to?(:readonly_attributes) &&
199
+ self.object.persisted? &&
200
+ column.respond_to?(:name) &&
201
+ object_class.readonly_attributes.include?(column.name.to_s)
202
+ end
203
+
204
+ def readonly_from_options?
205
+ options[:input_html] && options[:input_html][:readonly]
206
+ end
207
+
208
+ private
209
+
210
+ # Loosely based on
211
+ # https://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/validations/numericality.rb#L54-L59
212
+ def option_value(option, object)
213
+ case option
214
+ when Symbol
215
+ object.send(option)
216
+ when Proc
217
+ option.call(object)
218
+ else
219
+ option
220
+ end
221
+ end
195
222
  end
196
223
  end
197
224
  end
198
225
  end
199
-
@@ -69,6 +69,11 @@ module Formtastic
69
69
  include Base::Collections
70
70
  include Base::Choices
71
71
 
72
+ def initialize(*args)
73
+ super
74
+ raise Formtastic::UnsupportedEnumCollection if collection_from_enum?
75
+ end
76
+
72
77
  def to_html
73
78
  input_wrapping do
74
79
  choices_wrapping do
@@ -94,7 +99,7 @@ module Formtastic
94
99
  end
95
100
 
96
101
  def hidden_field_for_all
97
- if hidden_fields?
102
+ if hidden_fields_for_every?
98
103
  ''
99
104
  else
100
105
  options = {}
@@ -104,7 +109,7 @@ module Formtastic
104
109
  end
105
110
  end
106
111
 
107
- def hidden_fields?
112
+ def hidden_fields_for_every?
108
113
  options[:hidden_fields]
109
114
  end
110
115
 
@@ -165,7 +170,7 @@ module Formtastic
165
170
  protected
166
171
 
167
172
  def checkbox_input(choice)
168
- if hidden_fields?
173
+ if hidden_fields_for_every?
169
174
  check_box_with_hidden_input(choice)
170
175
  else
171
176
  check_box_without_hidden_input(choice)
@@ -175,11 +180,14 @@ module Formtastic
175
180
  def make_selected_values
176
181
  if object.respond_to?(method)
177
182
  selected_items = object.send(method)
178
-
179
183
  # Construct an array from the return value, regardless of the return type
180
184
  selected_items = [*selected_items].compact.flatten
181
185
 
182
- [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact
186
+ selected = []
187
+ selected_items.map do |selected_item|
188
+ selected_item_id = selected_item.id if selected_item.respond_to? :id
189
+ item = send_or_call_or_object(value_method, selected_item) || selected_item_id
190
+ end.compact
183
191
  else
184
192
  []
185
193
  end
@@ -31,7 +31,6 @@ module Formtastic
31
31
  include Base::Placeholder
32
32
 
33
33
  def to_html
34
- raise "The :color input requires the color_field form helper, which is only available in Rails 4+" unless builder.respond_to?(:color_field)
35
34
  input_wrapping do
36
35
  label_html <<
37
36
  builder.color_field(method, input_html_options)
@@ -67,8 +67,10 @@ module Formtastic
67
67
  class CountryInput
68
68
  include Base
69
69
 
70
+ CountrySelectPluginMissing = Class.new(StandardError)
71
+
70
72
  def to_html
71
- raise "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
73
+ raise CountrySelectPluginMissing, "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
72
74
  input_wrapping do
73
75
  label_html <<
74
76
  builder.country_select(method, priority_countries, input_options, input_html_options)
@@ -31,6 +31,10 @@ module Formtastic
31
31
  # `Section.all` for a `Post` form with an input for a `belongs_to :section` association.
32
32
  # You can override or customise this collection through the `:collection` option (see examples).
33
33
  #
34
+ # For radio inputs that map to ActiveRecord `enum` attributes, Formtastic will automatically
35
+ # load in your enum options to be used as the radio button choices. This can be overridden with
36
+ # the `:collection` option, or augmented with I18n translations. See examples below.
37
+ #
34
38
  # The way on which Formtastic renders the `value` attribute and label for each choice in the `:collection` is
35
39
  # customisable (see examples below). When not provided, we fall back to a list of methods to try on each
36
40
  # object such as `:to_label`, `:name` and `:to_s`, which are defined in the configurations
@@ -100,6 +104,22 @@ module Formtastic
100
104
  # @example Set HTML options on a specific radio input option with a 3rd element in the array for a collection member
101
105
  # <%= f.input :author, :as => :radio, :collection => [["Test", 'test'], ["Try", "try", {:disabled => true}]]
102
106
  #
107
+ # @example Using ActiveRecord enum attribute with i18n translation:
108
+ # # post.rb
109
+ # class Post < ActiveRecord::Base
110
+ # enum :status => [ :active, :archived ]
111
+ # end
112
+ # # en.yml
113
+ # en:
114
+ # activerecord:
115
+ # attributes:
116
+ # post:
117
+ # statuses:
118
+ # active: I am active!
119
+ # archived: I am archived!
120
+ # # form
121
+ # <%= f.input :status, :as => :radio %>
122
+ #
103
123
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
104
124
  # @see Formtastic::Inputs::RadioInput as an alternative for `belongs_to` associations
105
125
  #
@@ -8,6 +8,7 @@ module Formtastic
8
8
  # This is the default input choice when:
9
9
  #
10
10
  # * the database column type is an `:integer` and there is an association (`belongs_to`)
11
+ # * the database column type is an `:integer` and there is an enum defined (`enum`)
11
12
  # * the database column type is a `:string` and the `:collection` option is used
12
13
  # * there an object with an association, but no database column on the object (`has_many`, etc)
13
14
  # * there is no object and the `:collection` option is used
@@ -38,6 +39,13 @@ module Formtastic
38
39
  # `:to_s`, which are defined in the configurations `collection_label_methods` and
39
40
  # `collection_value_methods` (see examples below).
40
41
  #
42
+ # For select inputs that map to ActiveRecord `enum` attributes, Formtastic will automatically
43
+ # load in your enum options to be used as the select's options. This can be overridden with
44
+ # the `:collection` option, or augmented with I18n translations. See examples below.
45
+ # An error is raised if you try to render a multi-select with an enum, as ActiveRecord can
46
+ # only store one choice in the database.
47
+ #
48
+ #
41
49
  # @example Basic `belongs_to` example with full form context
42
50
  #
43
51
  # <%= semantic_form_for @post do |f| %>
@@ -124,6 +132,21 @@ module Formtastic
124
132
  # <%= f.input :author, :as => :select, :prompt => true %> => <option value="">Please select</option>
125
133
  # <%= f.input :author, :as => :select, :prompt => "Please select an author" %>
126
134
  #
135
+ # @example Using ActiveRecord enum attribute with i18n translation:
136
+ # # post.rb
137
+ # class Post < ActiveRecord::Base
138
+ # enum :status => [ :active, :archived ]
139
+ # end
140
+ # # en.yml
141
+ # en:
142
+ # activerecord:
143
+ # attributes:
144
+ # post:
145
+ # statuses:
146
+ # active: I am active!
147
+ # archived: I am archived!
148
+ # # form
149
+ # <%= f.input :status, :as => :select %>
127
150
  #
128
151
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
129
152
  # @see Formtastic::Inputs::CheckBoxesInput CheckBoxesInput as an alternative for `has_many` and `has_and_belongs_to_many` associations
@@ -134,6 +157,11 @@ module Formtastic
134
157
  include Base
135
158
  include Base::Collections
136
159
 
160
+ def initialize(*args)
161
+ super
162
+ raise Formtastic::UnsupportedEnumCollection if collection_from_enum? && multiple?
163
+ end
164
+
137
165
  def to_html
138
166
  input_wrapping do
139
167
  label_html <<
@@ -168,7 +196,7 @@ module Formtastic
168
196
  def extra_input_html_options
169
197
  {
170
198
  :multiple => multiple?,
171
- :name => (multiple? && Rails::VERSION::MAJOR >= 3) ? input_html_options_name_multiple : input_html_options_name
199
+ :name => multiple? ? input_html_options_name_multiple : input_html_options_name
172
200
  }
173
201
 
174
202
 
@@ -28,9 +28,19 @@ module Formtastic
28
28
  #
29
29
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
30
30
  #
31
- # @todo document :priority_zones option
32
- # @todo configurable default :priority_zones?
33
- class TimeZoneInput
31
+ # The priority_zones option:
32
+ # Since this input actually uses Rails' `time_zone_select` helper, the :priority_zones
33
+ # option needs to be an array of ActiveSupport::TimeZone objects.
34
+ #
35
+ # And you can configure default value using
36
+ #
37
+ # ```
38
+ # Formtastic::FormBuilder.priority_time_zones = [timezone1, timezone2]
39
+ # ```
40
+ #
41
+ # See http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/time_zone_select for more information.
42
+ #
43
+ class TimeZoneInput
34
44
  include Base
35
45
 
36
46
  def to_html
@@ -39,10 +49,10 @@ module Formtastic
39
49
  builder.time_zone_select(method, priority_zones, input_options, input_html_options)
40
50
  end
41
51
  end
42
-
52
+
43
53
  def priority_zones
44
- options[:priority_zones] || [] # TODO config?
54
+ options[:priority_zones] || Formtastic::FormBuilder.priority_time_zones
45
55
  end
46
56
  end
47
57
  end
48
- end
58
+ end