formtastic 3.1.3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) 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 +61 -0
  6. data/Gemfile.lock +140 -0
  7. data/MIT-LICENSE +1 -1
  8. data/{README.textile → README.md} +183 -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 +12 -16
  14. data/gemfiles/rails_6.0/Gemfile +5 -0
  15. data/gemfiles/rails_6.1/Gemfile +5 -0
  16. data/gemfiles/rails_7.0/Gemfile +5 -0
  17. data/gemfiles/rails_7.1/Gemfile +5 -0
  18. data/gemfiles/rails_edge/Gemfile +13 -0
  19. data/lib/formtastic/action_class_finder.rb +1 -0
  20. data/lib/formtastic/actions/base.rb +1 -0
  21. data/lib/formtastic/actions/button_action.rb +1 -0
  22. data/lib/formtastic/actions/buttonish.rb +1 -0
  23. data/lib/formtastic/actions/input_action.rb +1 -0
  24. data/lib/formtastic/actions/link_action.rb +1 -0
  25. data/lib/formtastic/actions.rb +7 -3
  26. data/lib/formtastic/deprecation.rb +2 -38
  27. data/lib/formtastic/engine.rb +4 -1
  28. data/lib/formtastic/form_builder.rb +12 -24
  29. data/lib/formtastic/helpers/action_helper.rb +2 -48
  30. data/lib/formtastic/helpers/actions_helper.rb +1 -0
  31. data/lib/formtastic/helpers/enum.rb +14 -0
  32. data/lib/formtastic/helpers/errors_helper.rb +3 -2
  33. data/lib/formtastic/helpers/fieldset_wrapper.rb +14 -9
  34. data/lib/formtastic/helpers/file_column_detection.rb +1 -0
  35. data/lib/formtastic/helpers/form_helper.rb +2 -1
  36. data/lib/formtastic/helpers/input_helper.rb +20 -76
  37. data/lib/formtastic/helpers/inputs_helper.rb +29 -23
  38. data/lib/formtastic/helpers/reflection.rb +1 -0
  39. data/lib/formtastic/helpers.rb +2 -2
  40. data/lib/formtastic/html_attributes.rb +1 -0
  41. data/lib/formtastic/i18n.rb +2 -1
  42. data/lib/formtastic/input_class_finder.rb +1 -0
  43. data/lib/formtastic/inputs/base/associations.rb +1 -0
  44. data/lib/formtastic/inputs/base/choices.rb +3 -2
  45. data/lib/formtastic/inputs/base/collections.rb +46 -10
  46. data/lib/formtastic/inputs/base/database.rb +5 -7
  47. data/lib/formtastic/inputs/base/datetime_pickerish.rb +1 -0
  48. data/lib/formtastic/inputs/base/errors.rb +7 -6
  49. data/lib/formtastic/inputs/base/fileish.rb +1 -0
  50. data/lib/formtastic/inputs/base/hints.rb +2 -1
  51. data/lib/formtastic/inputs/base/html.rb +9 -7
  52. data/lib/formtastic/inputs/base/labelling.rb +3 -2
  53. data/lib/formtastic/inputs/base/naming.rb +5 -4
  54. data/lib/formtastic/inputs/base/numeric.rb +1 -0
  55. data/lib/formtastic/inputs/base/options.rb +3 -3
  56. data/lib/formtastic/inputs/base/placeholder.rb +1 -0
  57. data/lib/formtastic/inputs/base/stringish.rb +1 -0
  58. data/lib/formtastic/inputs/base/timeish.rb +9 -4
  59. data/lib/formtastic/inputs/base/validations.rb +39 -12
  60. data/lib/formtastic/inputs/base/wrapping.rb +1 -0
  61. data/lib/formtastic/inputs/base.rb +3 -2
  62. data/lib/formtastic/inputs/boolean_input.rb +2 -1
  63. data/lib/formtastic/inputs/check_boxes_input.rb +15 -6
  64. data/lib/formtastic/inputs/color_input.rb +1 -1
  65. data/lib/formtastic/inputs/country_input.rb +4 -1
  66. data/lib/formtastic/inputs/datalist_input.rb +1 -0
  67. data/lib/formtastic/inputs/date_picker_input.rb +1 -0
  68. data/lib/formtastic/inputs/date_select_input.rb +1 -0
  69. data/lib/formtastic/inputs/datetime_picker_input.rb +1 -0
  70. data/lib/formtastic/inputs/datetime_select_input.rb +1 -0
  71. data/lib/formtastic/inputs/email_input.rb +1 -0
  72. data/lib/formtastic/inputs/file_input.rb +1 -0
  73. data/lib/formtastic/inputs/hidden_input.rb +3 -2
  74. data/lib/formtastic/inputs/number_input.rb +1 -0
  75. data/lib/formtastic/inputs/password_input.rb +1 -0
  76. data/lib/formtastic/inputs/phone_input.rb +1 -0
  77. data/lib/formtastic/inputs/radio_input.rb +21 -0
  78. data/lib/formtastic/inputs/range_input.rb +1 -0
  79. data/lib/formtastic/inputs/search_input.rb +1 -0
  80. data/lib/formtastic/inputs/select_input.rb +30 -1
  81. data/lib/formtastic/inputs/string_input.rb +1 -0
  82. data/lib/formtastic/inputs/text_input.rb +1 -0
  83. data/lib/formtastic/inputs/time_picker_input.rb +1 -0
  84. data/lib/formtastic/inputs/time_select_input.rb +1 -0
  85. data/lib/formtastic/inputs/time_zone_input.rb +17 -6
  86. data/lib/formtastic/inputs/url_input.rb +1 -0
  87. data/lib/formtastic/inputs.rb +33 -29
  88. data/lib/formtastic/localized_string.rb +1 -0
  89. data/lib/formtastic/localizer.rb +21 -22
  90. data/lib/formtastic/namespaced_class_finder.rb +8 -9
  91. data/lib/formtastic/version.rb +2 -1
  92. data/lib/formtastic.rb +10 -11
  93. data/lib/generators/formtastic/form/form_generator.rb +2 -1
  94. data/lib/generators/formtastic/input/input_generator.rb +47 -0
  95. data/lib/generators/formtastic/install/install_generator.rb +1 -0
  96. data/lib/generators/templates/formtastic.rb +15 -13
  97. data/lib/generators/templates/input.rb +19 -0
  98. data/sample/basic_inputs.html +1 -1
  99. data/script/integration-template.rb +73 -0
  100. data/script/integration.sh +19 -0
  101. data/spec/action_class_finder_spec.rb +2 -1
  102. data/spec/actions/button_action_spec.rb +21 -20
  103. data/spec/actions/generic_action_spec.rb +134 -133
  104. data/spec/actions/input_action_spec.rb +20 -19
  105. data/spec/actions/link_action_spec.rb +30 -29
  106. data/spec/builder/custom_builder_spec.rb +39 -22
  107. data/spec/builder/error_proc_spec.rb +6 -5
  108. data/spec/builder/semantic_fields_for_spec.rb +46 -45
  109. data/spec/fast_spec_helper.rb +13 -0
  110. data/spec/generators/formtastic/form/form_generator_spec.rb +33 -32
  111. data/spec/generators/formtastic/input/input_generator_spec.rb +125 -0
  112. data/spec/generators/formtastic/install/install_generator_spec.rb +10 -9
  113. data/spec/helpers/action_helper_spec.rb +329 -10
  114. data/spec/helpers/actions_helper_spec.rb +43 -42
  115. data/spec/helpers/form_helper_spec.rb +45 -38
  116. data/spec/helpers/input_helper_spec.rb +976 -2
  117. data/spec/helpers/inputs_helper_spec.rb +217 -202
  118. data/spec/helpers/reflection_helper_spec.rb +7 -6
  119. data/spec/helpers/semantic_errors_helper_spec.rb +26 -25
  120. data/spec/i18n_spec.rb +30 -29
  121. data/spec/input_class_finder_spec.rb +2 -1
  122. data/spec/inputs/base/collections_spec.rb +78 -0
  123. data/spec/inputs/base/validations_spec.rb +481 -0
  124. data/spec/inputs/boolean_input_spec.rb +73 -72
  125. data/spec/inputs/check_boxes_input_spec.rb +169 -121
  126. data/spec/inputs/color_input_spec.rb +53 -64
  127. data/spec/inputs/country_input_spec.rb +23 -22
  128. data/spec/inputs/custom_input_spec.rb +3 -6
  129. data/spec/inputs/datalist_input_spec.rb +3 -2
  130. data/spec/inputs/date_picker_input_spec.rb +114 -113
  131. data/spec/inputs/date_select_input_spec.rb +76 -61
  132. data/spec/inputs/datetime_picker_input_spec.rb +123 -122
  133. data/spec/inputs/datetime_select_input_spec.rb +85 -68
  134. data/spec/inputs/email_input_spec.rb +17 -16
  135. data/spec/inputs/file_input_spec.rb +18 -17
  136. data/spec/inputs/hidden_input_spec.rb +32 -31
  137. data/spec/inputs/include_blank_spec.rb +10 -9
  138. data/spec/inputs/label_spec.rb +26 -25
  139. data/spec/inputs/number_input_spec.rb +212 -211
  140. data/spec/inputs/password_input_spec.rb +17 -16
  141. data/spec/inputs/phone_input_spec.rb +17 -16
  142. data/spec/inputs/placeholder_spec.rb +18 -17
  143. data/spec/inputs/radio_input_spec.rb +92 -65
  144. data/spec/inputs/range_input_spec.rb +136 -135
  145. data/spec/inputs/readonly_spec.rb +51 -0
  146. data/spec/inputs/search_input_spec.rb +16 -15
  147. data/spec/inputs/select_input_spec.rb +209 -102
  148. data/spec/inputs/string_input_spec.rb +51 -50
  149. data/spec/inputs/text_input_spec.rb +34 -33
  150. data/spec/inputs/time_picker_input_spec.rb +115 -114
  151. data/spec/inputs/time_select_input_spec.rb +84 -70
  152. data/spec/inputs/time_zone_input_spec.rb +58 -31
  153. data/spec/inputs/url_input_spec.rb +17 -16
  154. data/spec/inputs/with_options_spec.rb +9 -8
  155. data/spec/localizer_spec.rb +18 -17
  156. data/spec/namespaced_class_finder_spec.rb +18 -6
  157. data/spec/schema.rb +22 -0
  158. data/spec/spec_helper.rb +172 -260
  159. data/spec/support/custom_macros.rb +74 -76
  160. data/spec/support/deprecation.rb +2 -1
  161. data/spec/support/shared_examples.rb +2 -1233
  162. data/spec/support/specialized_class_finder_shared_example.rb +1 -0
  163. data/spec/support/test_environment.rb +24 -9
  164. metadata +78 -170
  165. data/.travis.yml +0 -29
  166. data/Appraisals +0 -29
  167. data/CHANGELOG +0 -39
  168. data/DEPRECATIONS +0 -49
  169. data/gemfiles/rails_3.2.gemfile +0 -7
  170. data/gemfiles/rails_4.0.4.gemfile +0 -7
  171. data/gemfiles/rails_4.1.gemfile +0 -7
  172. data/gemfiles/rails_4.2.gemfile +0 -7
  173. data/gemfiles/rails_4.gemfile +0 -7
  174. data/gemfiles/rails_edge.gemfile +0 -10
  175. data/lib/formtastic/util.rb +0 -57
  176. data/spec/helpers/namespaced_action_helper_spec.rb +0 -43
  177. data/spec/helpers/namespaced_input_helper_spec.rb +0 -36
  178. data/spec/support/deferred_garbage_collection.rb +0 -21
  179. data/spec/util_spec.rb +0 -66
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
4
5
  module Naming
5
6
 
6
7
  def as
7
- self.class.name.split("::").last.underscore.gsub(/_input$/, '')
8
+ self.class.name.split("::")[-1].underscore.gsub(/_input$/, '')
8
9
  end
9
-
10
+
10
11
  def sanitized_object_name
11
12
  object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
12
13
  end
@@ -18,7 +19,7 @@ module Formtastic
18
19
  def attributized_method_name
19
20
  method.to_s.gsub(/_id$/, '').to_sym
20
21
  end
21
-
22
+
22
23
  def humanized_method_name
23
24
  if builder.label_str_method != :humanize
24
25
  # Special case where label_str_method should trump the human_attribute_name
@@ -39,4 +40,4 @@ module Formtastic
39
40
  end
40
41
  end
41
42
  end
42
- end
43
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -1,16 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
4
5
  module Options
5
-
6
+
6
7
  def input_options
7
8
  options.except(*formtastic_options)
8
9
  end
9
-
10
+
10
11
  def formtastic_options
11
12
  [:priority_countries, :priority_zones, :member_label, :member_value, :collection, :required, :label, :as, :hint, :input_html, :value_as_class, :class]
12
13
  end
13
-
14
14
  end
15
15
  end
16
16
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -85,6 +86,9 @@ module Formtastic
85
86
  # <%= f.input :publish_at, :as => :time_select, :include_blank => true %>
86
87
  # <%= f.input :publish_at, :as => :time_select, :include_blank => false %>
87
88
  #
89
+ # @example Provide a value for the field via selected
90
+ # <%= f.input :publish_at, :as => :datetime_select, :selected => DateTime.new(2018, 10, 4, 12, 00)
91
+ #
88
92
  # @todo Document i18n
89
93
  # @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
94
  # @todo Could we take the rendering from Rails' helpers and inject better HTML in and around it rather than re-inventing the whee?
@@ -153,10 +157,11 @@ module Formtastic
153
157
 
154
158
  def fragment_label_html(fragment)
155
159
  text = fragment_label(fragment)
156
- text.blank? ? "".html_safe : template.content_tag(:label, text, :for => fragment_id(fragment))
160
+ text.blank? ? +"".html_safe : template.content_tag(:label, text, :for => fragment_id(fragment))
157
161
  end
158
162
 
159
163
  def value
164
+ return input_options[:selected] if options.key?(:selected)
160
165
  object.send(method) if object && object.respond_to?(method)
161
166
  end
162
167
 
@@ -213,7 +218,7 @@ module Formtastic
213
218
  :class => "label"
214
219
  )
215
220
  else
216
- "".html_safe
221
+ +"".html_safe
217
222
  end
218
223
  end
219
224
 
@@ -224,7 +229,7 @@ module Formtastic
224
229
  end
225
230
 
226
231
  def hidden_fragments
227
- "".html_safe
232
+ +"".html_safe
228
233
  end
229
234
 
230
235
  def hidden_field_name(fragment)
@@ -238,4 +243,4 @@ module Formtastic
238
243
  end
239
244
  end
240
245
  end
241
- end
246
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -73,13 +74,11 @@ module Formtastic
73
74
  raise IndeterminableMinimumAttributeError if validation.options[:greater_than] && column? && [:float, :decimal].include?(column.type)
74
75
 
75
76
  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])
77
+ return option_value(validation.options[:greater_than_or_equal_to], object)
78
78
  end
79
79
 
80
80
  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)
81
+ return option_value(validation.options[:greater_than], object) + 1
83
82
  end
84
83
  end
85
84
  end
@@ -94,13 +93,11 @@ module Formtastic
94
93
  raise IndeterminableMaximumAttributeError if validation.options[:less_than] && column? && [:float, :decimal].include?(column.type)
95
94
 
96
95
  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])
96
+ return option_value(validation.options[:less_than_or_equal_to], object)
99
97
  end
100
98
 
101
99
  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)
100
+ return option_value(validation.options[:less_than], object) - 1
104
101
  end
105
102
  end
106
103
  end
@@ -136,9 +133,10 @@ module Formtastic
136
133
  return true if options[:required] == true
137
134
  return false if not_required_through_negated_validation?
138
135
  if validations?
139
- validations.select { |validator|
136
+ validations.any? { |validator|
140
137
  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))
138
+ validator_on = Array(validator.options[:on])
139
+ next false if (validator_on.exclude?(:save)) && ((object.new_record? && validator_on.exclude?(:create)) || (!object.new_record? && validator_on.exclude?(:update)))
142
140
  end
143
141
  case validator.kind
144
142
  when :presence
@@ -152,7 +150,7 @@ module Formtastic
152
150
  else
153
151
  false
154
152
  end
155
- }.any?
153
+ }
156
154
  else
157
155
  return responds_to_global_required? && !!builder.all_fields_required_by_default
158
156
  end
@@ -192,8 +190,37 @@ module Formtastic
192
190
  validation_limit || column_limit
193
191
  end
194
192
 
193
+ def readonly?
194
+ readonly_from_options? || readonly_attribute?
195
+ end
196
+
197
+ def readonly_attribute?
198
+ object_class = self.object.class
199
+ object_class.respond_to?(:readonly_attributes) &&
200
+ self.object.persisted? &&
201
+ column.respond_to?(:name) &&
202
+ object_class.readonly_attributes.include?(column.name.to_s)
203
+ end
204
+
205
+ def readonly_from_options?
206
+ options[:input_html] && options[:input_html][:readonly]
207
+ end
208
+
209
+ private
210
+
211
+ # Loosely based on
212
+ # https://github.com/rails/rails/blob/459e7cf62252558bbf65f582a230562ab1a76c5e/activemodel/lib/active_model/validations/numericality.rb#L65-L70
213
+ def option_value(option, object)
214
+ case option
215
+ when Symbol
216
+ object.send(option)
217
+ when Proc
218
+ option.call(object)
219
+ else
220
+ option
221
+ end
222
+ end
195
223
  end
196
224
  end
197
225
  end
198
226
  end
199
-
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  module Base
@@ -21,7 +22,7 @@ module Formtastic
21
22
  # Usefull for deprecating options.
22
23
  def warn_and_correct_option!(old_option_name, new_option_name)
23
24
  if options.key?(old_option_name)
24
- ::ActiveSupport::Deprecation.warn("The :#{old_option_name} option is deprecated in favour of :#{new_option_name} and will be removed from Formtastic in the next version", caller(6))
25
+ Deprecation.warn("The :#{old_option_name} option is deprecated in favour of :#{new_option_name} and will be removed from Formtastic in the next version", caller(6))
25
26
  options[new_option_name] = options.delete(old_option_name)
26
27
  end
27
28
  end
@@ -29,7 +30,7 @@ module Formtastic
29
30
  # Usefull for deprecating options.
30
31
  def warn_deprecated_option!(old_option_name, instructions)
31
32
  if options.key?(old_option_name)
32
- ::ActiveSupport::Deprecation.warn("The :#{old_option_name} option is deprecated in favour of `#{instructions}`. :#{old_option_name} will be removed in the next version", caller(6))
33
+ Deprecation.warn("The :#{old_option_name} option is deprecated in favour of `#{instructions}`. :#{old_option_name} will be removed in the next version", caller(6))
33
34
  end
34
35
  end
35
36
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # Boolean inputs are used to render an input for a single checkbox, typically for attributes
@@ -59,7 +60,7 @@ module Formtastic
59
60
  end
60
61
 
61
62
  def label_text_with_embedded_checkbox
62
- check_box_html << "" << label_text
63
+ check_box_html << +"" << label_text
63
64
  end
64
65
 
65
66
  def check_box_html
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -69,6 +70,11 @@ module Formtastic
69
70
  include Base::Collections
70
71
  include Base::Choices
71
72
 
73
+ def initialize(*args)
74
+ super
75
+ raise Formtastic::UnsupportedEnumCollection if collection_from_enum?
76
+ end
77
+
72
78
  def to_html
73
79
  input_wrapping do
74
80
  choices_wrapping do
@@ -94,8 +100,8 @@ module Formtastic
94
100
  end
95
101
 
96
102
  def hidden_field_for_all
97
- if hidden_fields?
98
- ''
103
+ if hidden_fields_for_every?
104
+ +''
99
105
  else
100
106
  options = {}
101
107
  options[:class] = [method.to_s.singularize, 'default'].join('_') if value_as_class?
@@ -104,7 +110,7 @@ module Formtastic
104
110
  end
105
111
  end
106
112
 
107
- def hidden_fields?
113
+ def hidden_fields_for_every?
108
114
  options[:hidden_fields]
109
115
  end
110
116
 
@@ -165,7 +171,7 @@ module Formtastic
165
171
  protected
166
172
 
167
173
  def checkbox_input(choice)
168
- if hidden_fields?
174
+ if hidden_fields_for_every?
169
175
  check_box_with_hidden_input(choice)
170
176
  else
171
177
  check_box_without_hidden_input(choice)
@@ -175,11 +181,14 @@ module Formtastic
175
181
  def make_selected_values
176
182
  if object.respond_to?(method)
177
183
  selected_items = object.send(method)
178
-
179
184
  # Construct an array from the return value, regardless of the return type
180
185
  selected_items = [*selected_items].compact.flatten
181
186
 
182
- [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact
187
+ selected = []
188
+ selected_items.map do |selected_item|
189
+ selected_item_id = selected_item.id if selected_item.respond_to? :id
190
+ item = send_or_call_or_object(value_method, selected_item) || selected_item_id
191
+ end.compact
183
192
  else
184
193
  []
185
194
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -31,7 +32,6 @@ module Formtastic
31
32
  include Base::Placeholder
32
33
 
33
34
  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
35
  input_wrapping do
36
36
  label_html <<
37
37
  builder.color_field(method, input_html_options)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # Outputs a country select input, wrapping around a regular country_select helper.
@@ -67,8 +68,10 @@ module Formtastic
67
68
  class CountryInput
68
69
  include Base
69
70
 
71
+ CountrySelectPluginMissing = Class.new(StandardError)
72
+
70
73
  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)
74
+ 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
75
  input_wrapping do
73
76
  label_html <<
74
77
  builder.country_select(method, priority_countries, input_options, input_html_options)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # Outputs a label and a text field, along with a datalist tag
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # Outputs a series of select boxes for the fragments that make up a date (year, month, day).
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -42,7 +43,7 @@ module Formtastic
42
43
  end
43
44
 
44
45
  def error_html
45
- ""
46
+ +""
46
47
  end
47
48
 
48
49
  def errors?
@@ -50,7 +51,7 @@ module Formtastic
50
51
  end
51
52
 
52
53
  def hint_html
53
- ""
54
+ +""
54
55
  end
55
56
 
56
57
  def hint?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -31,6 +32,10 @@ module Formtastic
31
32
  # `Section.all` for a `Post` form with an input for a `belongs_to :section` association.
32
33
  # You can override or customise this collection through the `:collection` option (see examples).
33
34
  #
35
+ # For radio inputs that map to ActiveRecord `enum` attributes, Formtastic will automatically
36
+ # load in your enum options to be used as the radio button choices. This can be overridden with
37
+ # the `:collection` option, or augmented with I18n translations. See examples below.
38
+ #
34
39
  # The way on which Formtastic renders the `value` attribute and label for each choice in the `:collection` is
35
40
  # customisable (see examples below). When not provided, we fall back to a list of methods to try on each
36
41
  # object such as `:to_label`, `:name` and `:to_s`, which are defined in the configurations
@@ -100,6 +105,22 @@ module Formtastic
100
105
  # @example Set HTML options on a specific radio input option with a 3rd element in the array for a collection member
101
106
  # <%= f.input :author, :as => :radio, :collection => [["Test", 'test'], ["Try", "try", {:disabled => true}]]
102
107
  #
108
+ # @example Using ActiveRecord enum attribute with i18n translation:
109
+ # # post.rb
110
+ # class Post < ActiveRecord::Base
111
+ # enum :status => [ :active, :archived ]
112
+ # end
113
+ # # en.yml
114
+ # en:
115
+ # activerecord:
116
+ # attributes:
117
+ # post:
118
+ # statuses:
119
+ # active: I am active!
120
+ # archived: I am archived!
121
+ # # form
122
+ # <%= f.input :status, :as => :radio %>
123
+ #
103
124
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
104
125
  # @see Formtastic::Inputs::RadioInput as an alternative for `belongs_to` associations
105
126
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # A select input is used to render a `<select>` tag with a series of options to choose from.
@@ -8,6 +9,7 @@ module Formtastic
8
9
  # This is the default input choice when:
9
10
  #
10
11
  # * the database column type is an `:integer` and there is an association (`belongs_to`)
12
+ # * the database column type is an `:integer` and there is an enum defined (`enum`)
11
13
  # * the database column type is a `:string` and the `:collection` option is used
12
14
  # * there an object with an association, but no database column on the object (`has_many`, etc)
13
15
  # * there is no object and the `:collection` option is used
@@ -38,6 +40,13 @@ module Formtastic
38
40
  # `:to_s`, which are defined in the configurations `collection_label_methods` and
39
41
  # `collection_value_methods` (see examples below).
40
42
  #
43
+ # For select inputs that map to ActiveRecord `enum` attributes, Formtastic will automatically
44
+ # load in your enum options to be used as the select's options. This can be overridden with
45
+ # the `:collection` option, or augmented with I18n translations. See examples below.
46
+ # An error is raised if you try to render a multi-select with an enum, as ActiveRecord can
47
+ # only store one choice in the database.
48
+ #
49
+ #
41
50
  # @example Basic `belongs_to` example with full form context
42
51
  #
43
52
  # <%= semantic_form_for @post do |f| %>
@@ -124,6 +133,21 @@ module Formtastic
124
133
  # <%= f.input :author, :as => :select, :prompt => true %> => <option value="">Please select</option>
125
134
  # <%= f.input :author, :as => :select, :prompt => "Please select an author" %>
126
135
  #
136
+ # @example Using ActiveRecord enum attribute with i18n translation:
137
+ # # post.rb
138
+ # class Post < ActiveRecord::Base
139
+ # enum :status => [ :active, :archived ]
140
+ # end
141
+ # # en.yml
142
+ # en:
143
+ # activerecord:
144
+ # attributes:
145
+ # post:
146
+ # statuses:
147
+ # active: I am active!
148
+ # archived: I am archived!
149
+ # # form
150
+ # <%= f.input :status, :as => :select %>
127
151
  #
128
152
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
129
153
  # @see Formtastic::Inputs::CheckBoxesInput CheckBoxesInput as an alternative for `has_many` and `has_and_belongs_to_many` associations
@@ -134,6 +158,11 @@ module Formtastic
134
158
  include Base
135
159
  include Base::Collections
136
160
 
161
+ def initialize(*args)
162
+ super
163
+ raise Formtastic::UnsupportedEnumCollection if collection_from_enum? && multiple?
164
+ end
165
+
137
166
  def to_html
138
167
  input_wrapping do
139
168
  label_html <<
@@ -168,7 +197,7 @@ module Formtastic
168
197
  def extra_input_html_options
169
198
  {
170
199
  :multiple => multiple?,
171
- :name => (multiple? && Rails::VERSION::MAJOR >= 3) ? input_html_options_name_multiple : input_html_options_name
200
+ :name => multiple? ? input_html_options_name_multiple : input_html_options_name
172
201
  }
173
202
 
174
203
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
  # Outputs a series of select boxes for the fragments that make up a time (hour, minute, second).
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4
 
@@ -28,9 +29,19 @@ module Formtastic
28
29
  #
29
30
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
30
31
  #
31
- # @todo document :priority_zones option
32
- # @todo configurable default :priority_zones?
33
- class TimeZoneInput
32
+ # The priority_zones option:
33
+ # Since this input actually uses Rails' `time_zone_select` helper, the :priority_zones
34
+ # option needs to be an array of ActiveSupport::TimeZone objects.
35
+ #
36
+ # And you can configure default value using
37
+ #
38
+ # ```
39
+ # Formtastic::FormBuilder.priority_time_zones = [timezone1, timezone2]
40
+ # ```
41
+ #
42
+ # See http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/time_zone_select for more information.
43
+ #
44
+ class TimeZoneInput
34
45
  include Base
35
46
 
36
47
  def to_html
@@ -39,10 +50,10 @@ module Formtastic
39
50
  builder.time_zone_select(method, priority_zones, input_options, input_html_options)
40
51
  end
41
52
  end
42
-
53
+
43
54
  def priority_zones
44
- options[:priority_zones] || [] # TODO config?
55
+ options[:priority_zones] || Formtastic::FormBuilder.priority_time_zones
45
56
  end
46
57
  end
47
58
  end
48
- end
59
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Formtastic
2
3
  module Inputs
3
4