formtastic 3.1.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +1 -0
- data/.github/workflows/test.yml +61 -0
- data/.gitignore +3 -2
- data/CHANGELOG.md +52 -0
- data/Gemfile.lock +105 -0
- data/MIT-LICENSE +1 -1
- data/{README.textile → README.md} +178 -167
- data/RELEASE_PROCESS +3 -1
- data/Rakefile +20 -1
- data/app/assets/stylesheets/formtastic.css +1 -1
- data/bin/appraisal +8 -0
- data/formtastic.gemspec +10 -16
- data/gemfiles/rails_5.2/Gemfile +5 -0
- data/gemfiles/rails_6.0/Gemfile +5 -0
- data/gemfiles/rails_6.1/Gemfile +5 -0
- data/gemfiles/rails_edge/Gemfile +13 -0
- data/lib/formtastic.rb +9 -11
- data/lib/formtastic/actions.rb +6 -3
- data/lib/formtastic/deprecation.rb +1 -38
- data/lib/formtastic/engine.rb +3 -1
- data/lib/formtastic/form_builder.rb +11 -24
- data/lib/formtastic/helpers.rb +1 -1
- data/lib/formtastic/helpers/action_helper.rb +1 -48
- data/lib/formtastic/helpers/enum.rb +13 -0
- data/lib/formtastic/helpers/errors_helper.rb +2 -2
- data/lib/formtastic/helpers/fieldset_wrapper.rb +13 -9
- data/lib/formtastic/helpers/form_helper.rb +1 -1
- data/lib/formtastic/helpers/input_helper.rb +23 -77
- data/lib/formtastic/helpers/inputs_helper.rb +27 -22
- data/lib/formtastic/i18n.rb +1 -1
- data/lib/formtastic/inputs.rb +32 -29
- data/lib/formtastic/inputs/base/choices.rb +1 -1
- data/lib/formtastic/inputs/base/collections.rb +43 -10
- data/lib/formtastic/inputs/base/database.rb +7 -2
- data/lib/formtastic/inputs/base/errors.rb +4 -4
- data/lib/formtastic/inputs/base/hints.rb +1 -1
- data/lib/formtastic/inputs/base/html.rb +7 -6
- data/lib/formtastic/inputs/base/naming.rb +4 -4
- data/lib/formtastic/inputs/base/options.rb +2 -3
- data/lib/formtastic/inputs/base/timeish.rb +5 -1
- data/lib/formtastic/inputs/base/validations.rb +38 -12
- data/lib/formtastic/inputs/check_boxes_input.rb +13 -5
- data/lib/formtastic/inputs/color_input.rb +0 -1
- data/lib/formtastic/inputs/country_input.rb +3 -1
- data/lib/formtastic/inputs/radio_input.rb +20 -0
- data/lib/formtastic/inputs/select_input.rb +29 -1
- data/lib/formtastic/inputs/time_zone_input.rb +16 -6
- data/lib/formtastic/localizer.rb +20 -22
- data/lib/formtastic/namespaced_class_finder.rb +1 -1
- data/lib/formtastic/version.rb +1 -1
- data/lib/generators/formtastic/form/form_generator.rb +1 -1
- data/lib/generators/formtastic/input/input_generator.rb +46 -0
- data/lib/generators/templates/formtastic.rb +14 -13
- data/lib/generators/templates/input.rb +19 -0
- data/sample/basic_inputs.html +1 -1
- data/script/integration-template.rb +74 -0
- data/script/integration.sh +19 -0
- data/spec/action_class_finder_spec.rb +1 -1
- data/spec/actions/button_action_spec.rb +8 -8
- data/spec/actions/generic_action_spec.rb +60 -60
- data/spec/actions/input_action_spec.rb +7 -7
- data/spec/actions/link_action_spec.rb +10 -10
- data/spec/builder/custom_builder_spec.rb +37 -21
- data/spec/builder/error_proc_spec.rb +4 -4
- data/spec/builder/semantic_fields_for_spec.rb +27 -27
- data/spec/fast_spec_helper.rb +12 -0
- data/spec/generators/formtastic/form/form_generator_spec.rb +25 -25
- data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
- data/spec/generators/formtastic/install/install_generator_spec.rb +9 -9
- data/spec/helpers/action_helper_spec.rb +328 -10
- data/spec/helpers/actions_helper_spec.rb +17 -17
- data/spec/helpers/form_helper_spec.rb +37 -37
- data/spec/helpers/input_helper_spec.rb +975 -2
- data/spec/helpers/inputs_helper_spec.rb +120 -105
- data/spec/helpers/reflection_helper_spec.rb +3 -3
- data/spec/helpers/semantic_errors_helper_spec.rb +22 -22
- data/spec/i18n_spec.rb +26 -26
- data/spec/input_class_finder_spec.rb +1 -1
- data/spec/inputs/base/collections_spec.rb +76 -0
- data/spec/inputs/base/validations_spec.rb +480 -0
- data/spec/inputs/boolean_input_spec.rb +55 -55
- data/spec/inputs/check_boxes_input_spec.rb +155 -108
- data/spec/inputs/color_input_spec.rb +51 -63
- data/spec/inputs/country_input_spec.rb +20 -20
- data/spec/inputs/custom_input_spec.rb +2 -6
- data/spec/inputs/datalist_input_spec.rb +1 -1
- data/spec/inputs/date_picker_input_spec.rb +42 -42
- data/spec/inputs/date_select_input_spec.rb +51 -37
- data/spec/inputs/datetime_picker_input_spec.rb +46 -46
- data/spec/inputs/datetime_select_input_spec.rb +53 -37
- data/spec/inputs/email_input_spec.rb +5 -5
- data/spec/inputs/file_input_spec.rb +6 -6
- data/spec/inputs/hidden_input_spec.rb +18 -18
- data/spec/inputs/include_blank_spec.rb +8 -8
- data/spec/inputs/label_spec.rb +20 -20
- data/spec/inputs/number_input_spec.rb +112 -112
- data/spec/inputs/password_input_spec.rb +5 -5
- data/spec/inputs/phone_input_spec.rb +5 -5
- data/spec/inputs/placeholder_spec.rb +5 -5
- data/spec/inputs/radio_input_spec.rb +84 -58
- data/spec/inputs/range_input_spec.rb +66 -66
- data/spec/inputs/readonly_spec.rb +50 -0
- data/spec/inputs/search_input_spec.rb +5 -5
- data/spec/inputs/select_input_spec.rb +149 -93
- data/spec/inputs/string_input_spec.rb +23 -23
- data/spec/inputs/text_input_spec.rb +16 -16
- data/spec/inputs/time_picker_input_spec.rb +43 -43
- data/spec/inputs/time_select_input_spec.rb +67 -54
- data/spec/inputs/time_zone_input_spec.rb +54 -28
- data/spec/inputs/url_input_spec.rb +5 -5
- data/spec/inputs/with_options_spec.rb +7 -7
- data/spec/localizer_spec.rb +17 -17
- data/spec/namespaced_class_finder_spec.rb +2 -2
- data/spec/schema.rb +21 -0
- data/spec/spec_helper.rb +165 -253
- data/spec/support/custom_macros.rb +72 -75
- data/spec/support/shared_examples.rb +0 -1232
- data/spec/support/test_environment.rb +23 -9
- metadata +69 -176
- data/.travis.yml +0 -29
- data/Appraisals +0 -29
- data/CHANGELOG +0 -31
- data/DEPRECATIONS +0 -49
- data/gemfiles/rails_3.2.gemfile +0 -7
- data/gemfiles/rails_4.0.4.gemfile +0 -7
- data/gemfiles/rails_4.1.gemfile +0 -7
- data/gemfiles/rails_4.2.gemfile +0 -7
- data/gemfiles/rails_4.gemfile +0 -7
- data/gemfiles/rails_edge.gemfile +0 -10
- data/lib/formtastic/util.rb +0 -57
- data/spec/helpers/namespaced_action_helper_spec.rb +0 -43
- data/spec/helpers/namespaced_input_helper_spec.rb +0 -36
- data/spec/support/deferred_garbage_collection.rb +0 -21
- data/spec/util_spec.rb +0 -66
|
@@ -163,7 +163,7 @@ module Formtastic
|
|
|
163
163
|
class_names << @@default_form_class
|
|
164
164
|
model_class_name = case record_or_name_or_array
|
|
165
165
|
when String, Symbol then record_or_name_or_array.to_s # :post => "post"
|
|
166
|
-
when Array then options[:as] || singularizer.call(record_or_name_or_array.
|
|
166
|
+
when Array then options[:as] || singularizer.call(record_or_name_or_array[-1].class) # [@post, @comment] # => "comment"
|
|
167
167
|
else options[:as] || singularizer.call(record_or_name_or_array.class) # @post => "post"
|
|
168
168
|
end
|
|
169
169
|
class_names << @@default_form_model_class_proc.call(model_class_name)
|
|
@@ -36,10 +36,8 @@ module Formtastic
|
|
|
36
36
|
# @see Formtastic::Helpers::InputsHelper#inputs
|
|
37
37
|
# @see Formtastic::Helpers::FormHelper#semantic_form_for
|
|
38
38
|
module InputHelper
|
|
39
|
-
INPUT_CLASS_DEPRECATION = 'configure Formtastic::FormBuilder.input_class_finder instead (upgrade guide on wiki: http://bit.ly/1F9QtKc )'.freeze
|
|
40
|
-
private_constant(:INPUT_CLASS_DEPRECATION)
|
|
41
|
-
|
|
42
39
|
include Formtastic::Helpers::Reflection
|
|
40
|
+
include Formtastic::Helpers::Enum
|
|
43
41
|
include Formtastic::Helpers::FileColumnDetection
|
|
44
42
|
|
|
45
43
|
# Returns a chunk of HTML markup for a given `method` on the form object, wrapped in
|
|
@@ -134,6 +132,7 @@ module Formtastic
|
|
|
134
132
|
#
|
|
135
133
|
# @option options :input_html [Hash]
|
|
136
134
|
# Override or add to the HTML attributes to be passed down to the `<input>` tag
|
|
135
|
+
# (If you use attr_readonly method in your model, formtastic will automatically set those attributes's input readonly)
|
|
137
136
|
#
|
|
138
137
|
# @option options :wrapper_html [Hash]
|
|
139
138
|
# Override or add to the HTML attributes to be passed down to the wrapping `<li>` tag
|
|
@@ -235,7 +234,7 @@ module Formtastic
|
|
|
235
234
|
options = options.dup # Allow options to be shared without being tainted by Formtastic
|
|
236
235
|
options[:as] ||= default_input_type(method, options)
|
|
237
236
|
|
|
238
|
-
klass =
|
|
237
|
+
klass = namespaced_input_class(options[:as])
|
|
239
238
|
|
|
240
239
|
klass.new(self, template, @object, @object_name, method, options).to_html
|
|
241
240
|
end
|
|
@@ -259,7 +258,8 @@ module Formtastic
|
|
|
259
258
|
return :file if is_file?(method, options)
|
|
260
259
|
end
|
|
261
260
|
|
|
262
|
-
|
|
261
|
+
column = column_for(method)
|
|
262
|
+
if column && column.type
|
|
263
263
|
# Special cases where the column type doesn't map to an input method.
|
|
264
264
|
case column.type
|
|
265
265
|
when :string
|
|
@@ -273,6 +273,7 @@ module Formtastic
|
|
|
273
273
|
return :color if method.to_s =~ /color/
|
|
274
274
|
when :integer
|
|
275
275
|
return :select if reflection_for(method)
|
|
276
|
+
return :select if enum_for(method)
|
|
276
277
|
return :number
|
|
277
278
|
when :float, :decimal
|
|
278
279
|
return :number
|
|
@@ -282,6 +283,10 @@ module Formtastic
|
|
|
282
283
|
return :time_select
|
|
283
284
|
when :date
|
|
284
285
|
return :date_select
|
|
286
|
+
when :hstore, :json, :jsonb
|
|
287
|
+
return :text
|
|
288
|
+
when :citext, :inet
|
|
289
|
+
return :string
|
|
285
290
|
end
|
|
286
291
|
|
|
287
292
|
# Try look for hints in options hash. Quite common senario: Enum keys stored as string in the database.
|
|
@@ -296,12 +301,20 @@ module Formtastic
|
|
|
296
301
|
end
|
|
297
302
|
|
|
298
303
|
# Get a column object for a specified attribute method - if possible.
|
|
304
|
+
# @return [ActiveModel::Type::Value, #type] in case of rails 5 attributes api
|
|
305
|
+
# @return [ActiveRecord::ConnectionAdapters::Column] in case of rails 4
|
|
299
306
|
def column_for(method) # @private
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
case
|
|
308
|
+
when @object.class.respond_to?(:type_for_attribute)
|
|
309
|
+
@object.class.type_for_attribute(method.to_s)
|
|
310
|
+
when @object.class.respond_to?(:column_for_attribute)
|
|
311
|
+
@object.class.column_for_attribute(method)
|
|
312
|
+
when @object.respond_to?(:column_for_attribute)
|
|
313
|
+
# Remove deprecation wrapper & review after Rails 5.0 ships
|
|
314
|
+
ActiveSupport::Deprecation.silence do
|
|
315
|
+
@object.column_for_attribute(method)
|
|
316
|
+
end
|
|
317
|
+
else nil
|
|
305
318
|
end
|
|
306
319
|
end
|
|
307
320
|
|
|
@@ -331,73 +344,6 @@ module Formtastic
|
|
|
331
344
|
rescue Formtastic::InputClassFinder::NotFoundError
|
|
332
345
|
raise Formtastic::UnknownInputError, "Unable to find input #{$!.message}"
|
|
333
346
|
end
|
|
334
|
-
|
|
335
|
-
# @api private
|
|
336
|
-
# @deprecated Use {#namespaced_input_class} instead.
|
|
337
|
-
def input_class(as)
|
|
338
|
-
return namespaced_input_class(as) if input_class_finder
|
|
339
|
-
|
|
340
|
-
input_class_deprecation_warning(__method__)
|
|
341
|
-
|
|
342
|
-
@input_classes_cache ||= {}
|
|
343
|
-
@input_classes_cache[as] ||= begin
|
|
344
|
-
config = Rails.application.config
|
|
345
|
-
use_const_defined = config.respond_to?(:eager_load) ? config.eager_load : config.cache_classes
|
|
346
|
-
use_const_defined ? input_class_with_const_defined(as) : input_class_by_trying(as)
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
# @api private
|
|
351
|
-
# @deprecated Use {InputClassFinder#find} instead.
|
|
352
|
-
# prevent exceptions in production environment for better performance
|
|
353
|
-
def input_class_with_const_defined(as)
|
|
354
|
-
input_class_name = custom_input_class_name(as)
|
|
355
|
-
|
|
356
|
-
if ::Object.const_defined?(input_class_name)
|
|
357
|
-
input_class_name.constantize
|
|
358
|
-
elsif Formtastic::Inputs.const_defined?(input_class_name)
|
|
359
|
-
standard_input_class_name(as).constantize
|
|
360
|
-
else
|
|
361
|
-
raise Formtastic::UnknownInputError, "Unable to find input class #{input_class_name}"
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
# @api private
|
|
366
|
-
# @deprecated Use {InputClassFinder#find} instead.
|
|
367
|
-
# use auto-loading in development environment
|
|
368
|
-
def input_class_by_trying(as)
|
|
369
|
-
begin
|
|
370
|
-
custom_input_class_name(as).constantize
|
|
371
|
-
rescue NameError
|
|
372
|
-
standard_input_class_name(as).constantize
|
|
373
|
-
end
|
|
374
|
-
rescue NameError
|
|
375
|
-
raise Formtastic::UnknownInputError, "Unable to find input class for #{as}"
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
# @api private
|
|
379
|
-
# @deprecated Use {InputClassFinder#class_name} instead.
|
|
380
|
-
# :as => :string # => StringInput
|
|
381
|
-
def custom_input_class_name(as)
|
|
382
|
-
input_class_deprecation_warning(__method__)
|
|
383
|
-
"#{as.to_s.camelize}Input"
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
# @api private
|
|
387
|
-
# @deprecated Use {InputClassFinder#class_name} instead.
|
|
388
|
-
# :as => :string # => {Formtastic::Inputs::StringInput}
|
|
389
|
-
def standard_input_class_name(as)
|
|
390
|
-
input_class_deprecation_warning(__method__)
|
|
391
|
-
"Formtastic::Inputs::#{as.to_s.camelize}Input"
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
private
|
|
395
|
-
|
|
396
|
-
def input_class_deprecation_warning(method)
|
|
397
|
-
@input_class_deprecation_warned ||=
|
|
398
|
-
Formtastic.deprecation.deprecation_warning(method, INPUT_CLASS_DEPRECATION, caller(2))
|
|
399
|
-
end
|
|
400
|
-
|
|
401
347
|
end
|
|
402
348
|
end
|
|
403
349
|
end
|
|
@@ -47,10 +47,6 @@ module Formtastic
|
|
|
47
47
|
include Formtastic::Helpers::FieldsetWrapper
|
|
48
48
|
include Formtastic::LocalizedString
|
|
49
49
|
|
|
50
|
-
# Which columns to skip when automatically rendering a form without any fields specified.
|
|
51
|
-
SKIPPED_COLUMNS = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
|
|
52
|
-
|
|
53
|
-
|
|
54
50
|
# {#inputs} creates an input fieldset and ol tag wrapping for use around a set of inputs. It can be
|
|
55
51
|
# called either with a block (in which you can do the usual Rails form stuff, HTML, ERB, etc),
|
|
56
52
|
# or with a list of fields (accepting all default arguments and options). These two examples
|
|
@@ -136,7 +132,7 @@ module Formtastic
|
|
|
136
132
|
# <% end %>
|
|
137
133
|
# <% end %>
|
|
138
134
|
#
|
|
139
|
-
# {#inputs} also provides a DSL similar to `fields_for` / `semantic_fields_for` to reduce the
|
|
135
|
+
# {#inputs} also provides a DSL similar to `fields_for` / `semantic_fields_for` to reduce the
|
|
140
136
|
# lines of code a little:
|
|
141
137
|
#
|
|
142
138
|
# <% semantic_form_for @user do |f| %>
|
|
@@ -162,7 +158,7 @@ module Formtastic
|
|
|
162
158
|
# All options except `:name`, `:title` and `:for` will be passed down to the fieldset as HTML
|
|
163
159
|
# attributes (id, class, style, etc).
|
|
164
160
|
#
|
|
165
|
-
# When nesting `inputs()` inside another `inputs()` block, the nested content will
|
|
161
|
+
# When nesting `inputs()` inside another `inputs()` block, the nested content will
|
|
166
162
|
# automatically be wrapped in an `<li>` tag to preserve the HTML validity (a `<fieldset>`
|
|
167
163
|
# cannot be a direct descendant of an `<ol>`.
|
|
168
164
|
#
|
|
@@ -183,12 +179,12 @@ module Formtastic
|
|
|
183
179
|
# <% end %>
|
|
184
180
|
#
|
|
185
181
|
# @example Quick form: Skip one or more fields
|
|
186
|
-
# <%= f.inputs
|
|
187
|
-
# <%= f.inputs
|
|
182
|
+
# <%= f.inputs :except => [:featured, :something_for_admin_only] %>
|
|
183
|
+
# <%= f.inputs :except => :featured %>
|
|
188
184
|
#
|
|
189
185
|
# @example Short hand: Render inputs for a named set of attributes and simple associations on the model, with all default arguments and options
|
|
190
186
|
# <% semantic_form_for @post do |form| %>
|
|
191
|
-
# <%= f.inputs
|
|
187
|
+
# <%= f.inputs :title, :body, :user, :categories %>
|
|
192
188
|
# <% end %>
|
|
193
189
|
#
|
|
194
190
|
# @example Block: Render inputs for attributes and simple associations with full control over arguments and options
|
|
@@ -219,7 +215,7 @@ module Formtastic
|
|
|
219
215
|
# <%= f.input :title ... %>
|
|
220
216
|
# <%= f.input :body ... %>
|
|
221
217
|
# <% end %>
|
|
222
|
-
# <%= f.inputs
|
|
218
|
+
# <%= f.inputs :name => 'Advanced options:' do %>
|
|
223
219
|
# <%= f.input :user ... %>
|
|
224
220
|
# <%= f.input :categories ... %>
|
|
225
221
|
# <% end %>
|
|
@@ -283,7 +279,7 @@ module Formtastic
|
|
|
283
279
|
def inputs(*args, &block)
|
|
284
280
|
wrap_it = @already_in_an_inputs_block ? true : false
|
|
285
281
|
@already_in_an_inputs_block = true
|
|
286
|
-
|
|
282
|
+
|
|
287
283
|
title = field_set_title_from_args(*args)
|
|
288
284
|
html_options = args.extract_options!
|
|
289
285
|
html_options[:class] ||= "inputs"
|
|
@@ -303,21 +299,21 @@ module Formtastic
|
|
|
303
299
|
field_set_and_list_wrapping(*((args << html_options) << contents))
|
|
304
300
|
end
|
|
305
301
|
end
|
|
306
|
-
|
|
302
|
+
|
|
307
303
|
out = template.content_tag(:li, out, :class => "input") if wrap_it
|
|
308
304
|
@already_in_an_inputs_block = wrap_it
|
|
309
305
|
out
|
|
310
306
|
end
|
|
311
307
|
|
|
312
308
|
protected
|
|
313
|
-
|
|
309
|
+
|
|
314
310
|
def default_columns_for_object
|
|
315
311
|
cols = association_columns(:belongs_to)
|
|
316
312
|
cols += content_columns
|
|
317
|
-
cols -=
|
|
313
|
+
cols -= skipped_columns
|
|
318
314
|
cols.compact
|
|
319
315
|
end
|
|
320
|
-
|
|
316
|
+
|
|
321
317
|
def fieldset_contents_from_column_list(columns)
|
|
322
318
|
columns.collect do |method|
|
|
323
319
|
if @object
|
|
@@ -328,13 +324,13 @@ module Formtastic
|
|
|
328
324
|
elsif @object.class.respond_to?(:associations)
|
|
329
325
|
if (@object.class.associations[method.to_sym] && @object.class.associations[method.to_sym].options[:polymorphic] == true)
|
|
330
326
|
raise PolymorphicInputWithoutCollectionError.new("Please provide a collection for :#{method} input (you'll need to use block form syntax). Inputs for polymorphic associations can only be used when an explicit :collection is provided.")
|
|
331
|
-
end
|
|
332
|
-
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
333
329
|
end
|
|
334
330
|
input(method.to_sym)
|
|
335
331
|
end
|
|
336
332
|
end
|
|
337
|
-
|
|
333
|
+
|
|
338
334
|
# Collects association columns (relation columns) for the current form object class. Skips
|
|
339
335
|
# polymorphic associations because we can't guess which class to use for an automatically
|
|
340
336
|
# generated input.
|
|
@@ -343,7 +339,7 @@ module Formtastic
|
|
|
343
339
|
@object.class.reflections.collect do |name, association_reflection|
|
|
344
340
|
if by_associations.present?
|
|
345
341
|
if by_associations.include?(association_reflection.macro) && association_reflection.options[:polymorphic] != true
|
|
346
|
-
name
|
|
342
|
+
name
|
|
347
343
|
end
|
|
348
344
|
else
|
|
349
345
|
name
|
|
@@ -354,12 +350,21 @@ module Formtastic
|
|
|
354
350
|
end
|
|
355
351
|
end
|
|
356
352
|
|
|
353
|
+
# Collects all foreign key columns
|
|
354
|
+
def foreign_key_columns # @private
|
|
355
|
+
if @object.present? && @object.class.respond_to?(:reflect_on_all_associations)
|
|
356
|
+
@object.class.reflect_on_all_associations(:belongs_to).map{ |reflection| reflection.foreign_key.to_sym }
|
|
357
|
+
else
|
|
358
|
+
[]
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
357
362
|
# Collects content columns (non-relation columns) for the current form object class.
|
|
358
363
|
def content_columns # @private
|
|
359
364
|
# TODO: NameError is raised by Inflector.constantize. Consider checking if it exists instead.
|
|
360
365
|
begin klass = model_name.constantize; rescue NameError; return [] end
|
|
361
366
|
return [] unless klass.respond_to?(:content_columns)
|
|
362
|
-
klass.content_columns.collect { |c| c.name.to_sym }.compact
|
|
367
|
+
klass.content_columns.collect { |c| c.name.to_sym }.compact - foreign_key_columns
|
|
363
368
|
end
|
|
364
369
|
|
|
365
370
|
# Deals with :for option when it's supplied to inputs methods. Additional
|
|
@@ -377,10 +382,10 @@ module Formtastic
|
|
|
377
382
|
lambda do |f|
|
|
378
383
|
contents = f.inputs(*args) do
|
|
379
384
|
if block.arity == 1 # for backwards compatibility with REE & Ruby 1.8.x
|
|
380
|
-
|
|
385
|
+
yield(f)
|
|
381
386
|
else
|
|
382
387
|
index = parent_child_index(options[:parent]) if options[:parent]
|
|
383
|
-
|
|
388
|
+
yield(f, index)
|
|
384
389
|
end
|
|
385
390
|
end
|
|
386
391
|
template.concat(contents)
|
data/lib/formtastic/i18n.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Formtastic
|
|
|
23
23
|
options = args.extract_options!
|
|
24
24
|
options.reverse_merge!(:default => DEFAULT_VALUES[key])
|
|
25
25
|
options[:scope] = [DEFAULT_SCOPE, options[:scope]].flatten.compact
|
|
26
|
-
::I18n.translate(key, *
|
|
26
|
+
::I18n.translate(key, *args, **options)
|
|
27
27
|
end
|
|
28
28
|
alias :t :translate
|
|
29
29
|
|
data/lib/formtastic/inputs.rb
CHANGED
|
@@ -4,36 +4,39 @@ module Formtastic
|
|
|
4
4
|
|
|
5
5
|
autoload :Base
|
|
6
6
|
autoload :Basic
|
|
7
|
-
autoload :BooleanInput
|
|
8
|
-
autoload :CheckBoxesInput
|
|
9
|
-
autoload :ColorInput
|
|
10
|
-
autoload :CountryInput
|
|
11
|
-
autoload :DatalistInput
|
|
12
|
-
autoload :DateInput
|
|
13
|
-
autoload :DatePickerInput
|
|
14
|
-
autoload :DatetimePickerInput
|
|
15
|
-
autoload :DateSelectInput
|
|
16
|
-
autoload :DatetimeInput
|
|
17
|
-
autoload :DatetimeSelectInput
|
|
18
|
-
autoload :EmailInput
|
|
19
|
-
autoload :FileInput
|
|
20
|
-
autoload :HiddenInput
|
|
21
|
-
autoload :NumberInput
|
|
22
|
-
autoload :NumericInput
|
|
23
|
-
autoload :PasswordInput
|
|
24
|
-
autoload :PhoneInput
|
|
25
|
-
autoload :RadioInput
|
|
26
|
-
autoload :RangeInput
|
|
27
|
-
autoload :SearchInput
|
|
28
|
-
autoload :SelectInput
|
|
29
|
-
autoload :StringInput
|
|
30
|
-
autoload :TextInput
|
|
31
|
-
autoload :TimeInput
|
|
32
|
-
autoload :TimePickerInput
|
|
33
|
-
autoload :TimeSelectInput
|
|
34
|
-
autoload :TimeZoneInput
|
|
35
7
|
autoload :Timeish
|
|
36
|
-
|
|
8
|
+
|
|
9
|
+
eager_autoload do
|
|
10
|
+
autoload :BooleanInput
|
|
11
|
+
autoload :CheckBoxesInput
|
|
12
|
+
autoload :ColorInput
|
|
13
|
+
autoload :CountryInput
|
|
14
|
+
autoload :DatalistInput
|
|
15
|
+
autoload :DateInput
|
|
16
|
+
autoload :DatePickerInput
|
|
17
|
+
autoload :DatetimePickerInput
|
|
18
|
+
autoload :DateSelectInput
|
|
19
|
+
autoload :DatetimeInput
|
|
20
|
+
autoload :DatetimeSelectInput
|
|
21
|
+
autoload :EmailInput
|
|
22
|
+
autoload :FileInput
|
|
23
|
+
autoload :HiddenInput
|
|
24
|
+
autoload :NumberInput
|
|
25
|
+
autoload :NumericInput
|
|
26
|
+
autoload :PasswordInput
|
|
27
|
+
autoload :PhoneInput
|
|
28
|
+
autoload :RadioInput
|
|
29
|
+
autoload :RangeInput
|
|
30
|
+
autoload :SearchInput
|
|
31
|
+
autoload :SelectInput
|
|
32
|
+
autoload :StringInput
|
|
33
|
+
autoload :TextInput
|
|
34
|
+
autoload :TimeInput
|
|
35
|
+
autoload :TimePickerInput
|
|
36
|
+
autoload :TimeSelectInput
|
|
37
|
+
autoload :TimeZoneInput
|
|
38
|
+
autoload :UrlInput
|
|
39
|
+
end
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
|
|
@@ -12,7 +12,7 @@ module Formtastic
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def value_method
|
|
15
|
-
@value_method ||= (value_method_from_options || label_and_value_method
|
|
15
|
+
@value_method ||= (value_method_from_options || label_and_value_method[-1])
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def value_method_from_options
|
|
@@ -24,7 +24,7 @@ module Formtastic
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def label_and_value_method_from_collection(_collection)
|
|
27
|
-
sample = _collection.first || _collection
|
|
27
|
+
sample = _collection.first || _collection[-1]
|
|
28
28
|
|
|
29
29
|
case sample
|
|
30
30
|
when Array
|
|
@@ -43,16 +43,16 @@ module Formtastic
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def raw_collection
|
|
46
|
-
@raw_collection ||= (collection_from_options || collection_from_association || collection_for_boolean)
|
|
46
|
+
@raw_collection ||= (collection_from_options || collection_from_enum || collection_from_association || collection_for_boolean)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def collection
|
|
50
50
|
# Return if we have a plain string
|
|
51
51
|
return raw_collection if raw_collection.is_a?(String)
|
|
52
52
|
|
|
53
|
-
# Return if we have an Array of strings,
|
|
53
|
+
# Return if we have an Array of strings, integers or arrays
|
|
54
54
|
return raw_collection if (raw_collection.instance_of?(Array) || raw_collection.instance_of?(Range)) &&
|
|
55
|
-
[Array,
|
|
55
|
+
([Array, String].include?(raw_collection.first.class) || raw_collection.first.is_a?(Integer)) &&
|
|
56
56
|
!(options.include?(:member_label) || options.include?(:member_value))
|
|
57
57
|
|
|
58
58
|
raw_collection.map { |o| [send_or_call(label_method, o), send_or_call(value_method, o)] }
|
|
@@ -83,15 +83,48 @@ module Formtastic
|
|
|
83
83
|
|
|
84
84
|
scope_conditions = conditions_from_reflection.empty? ? nil : {:conditions => conditions_from_reflection}
|
|
85
85
|
where_conditions = (scope_conditions && scope_conditions[:conditions]) || {}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
|
|
87
|
+
reflection.klass.where(where_conditions)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Assuming the following model:
|
|
92
|
+
#
|
|
93
|
+
# class Post < ActiveRecord::Base
|
|
94
|
+
# enum :status => [ :active, :archived ]
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# We would end up with a collection like this:
|
|
98
|
+
#
|
|
99
|
+
# [["Active", "active"], ["Archived", "archived"]
|
|
100
|
+
#
|
|
101
|
+
# The first element in each array uses String#humanize, but I18n
|
|
102
|
+
# translations are available too. Set them with the following structure.
|
|
103
|
+
#
|
|
104
|
+
# en:
|
|
105
|
+
# activerecord:
|
|
106
|
+
# attributes:
|
|
107
|
+
# post:
|
|
108
|
+
# statuses:
|
|
109
|
+
# active: Custom Active Label Here
|
|
110
|
+
# archived: Custom Archived Label Here
|
|
111
|
+
def collection_from_enum
|
|
112
|
+
if collection_from_enum?
|
|
113
|
+
method_name = method.to_s
|
|
114
|
+
|
|
115
|
+
enum_options_hash = object.defined_enums[method_name]
|
|
116
|
+
enum_options_hash.map do |name, value|
|
|
117
|
+
key = "activerecord.attributes.#{object_name}.#{method_name.pluralize}.#{name}"
|
|
118
|
+
label = ::I18n.translate(key, :default => name.humanize)
|
|
119
|
+
[label, name]
|
|
91
120
|
end
|
|
92
121
|
end
|
|
93
122
|
end
|
|
94
123
|
|
|
124
|
+
def collection_from_enum?
|
|
125
|
+
object.respond_to?(:defined_enums) && object.defined_enums.has_key?(method.to_s)
|
|
126
|
+
end
|
|
127
|
+
|
|
95
128
|
def collection_for_boolean
|
|
96
129
|
true_text = options[:true] || Formtastic::I18n.t(:yes)
|
|
97
130
|
false_text = options[:false] || Formtastic::I18n.t(:no)
|