formtastic 1.2.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +279 -0
  5. data/Gemfile +3 -0
  6. data/README.textile +155 -172
  7. data/RELEASE_PROCESS +7 -0
  8. data/Rakefile +52 -0
  9. data/app/assets/stylesheets/formtastic.css +275 -0
  10. data/app/assets/stylesheets/formtastic_ie6.css +27 -0
  11. data/app/assets/stylesheets/formtastic_ie7.css +17 -0
  12. data/formtastic.gemspec +51 -0
  13. data/lib/formtastic.rb +21 -1960
  14. data/lib/formtastic/engine.rb +7 -0
  15. data/lib/formtastic/form_builder.rb +83 -0
  16. data/lib/formtastic/helpers.rb +16 -0
  17. data/lib/formtastic/helpers/buttons_helper.rb +277 -0
  18. data/lib/formtastic/helpers/errors_helper.rb +113 -0
  19. data/lib/formtastic/helpers/fieldset_wrapper.rb +75 -0
  20. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  21. data/lib/formtastic/helpers/form_helper.rb +198 -0
  22. data/lib/formtastic/helpers/input_helper.rb +366 -0
  23. data/lib/formtastic/helpers/inputs_helper.rb +392 -0
  24. data/lib/formtastic/helpers/reflection.rb +33 -0
  25. data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
  26. data/lib/formtastic/html_attributes.rb +21 -0
  27. data/lib/formtastic/i18n.rb +1 -0
  28. data/lib/formtastic/inputs.rb +31 -0
  29. data/lib/formtastic/inputs/base.rb +61 -0
  30. data/lib/formtastic/inputs/base/associations.rb +31 -0
  31. data/lib/formtastic/inputs/base/choices.rb +103 -0
  32. data/lib/formtastic/inputs/base/collections.rb +94 -0
  33. data/lib/formtastic/inputs/base/database.rb +17 -0
  34. data/lib/formtastic/inputs/base/errors.rb +58 -0
  35. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  36. data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
  37. data/lib/formtastic/inputs/base/hints.rb +31 -0
  38. data/lib/formtastic/inputs/base/html.rb +52 -0
  39. data/lib/formtastic/inputs/base/labelling.rb +55 -0
  40. data/lib/formtastic/inputs/base/naming.rb +42 -0
  41. data/lib/formtastic/inputs/base/options.rb +18 -0
  42. data/lib/formtastic/inputs/base/stringish.rb +35 -0
  43. data/lib/formtastic/inputs/base/timeish.rb +128 -0
  44. data/lib/formtastic/inputs/base/validations.rb +166 -0
  45. data/lib/formtastic/inputs/base/wrapping.rb +40 -0
  46. data/lib/formtastic/inputs/boolean_input.rb +96 -0
  47. data/lib/formtastic/inputs/check_boxes_input.rb +179 -0
  48. data/lib/formtastic/inputs/country_input.rb +66 -0
  49. data/lib/formtastic/inputs/date_input.rb +14 -0
  50. data/lib/formtastic/inputs/datetime_input.rb +9 -0
  51. data/lib/formtastic/inputs/email_input.rb +40 -0
  52. data/lib/formtastic/inputs/file_input.rb +42 -0
  53. data/lib/formtastic/inputs/hidden_input.rb +66 -0
  54. data/lib/formtastic/inputs/number_input.rb +118 -0
  55. data/lib/formtastic/inputs/numeric_input.rb +21 -0
  56. data/lib/formtastic/inputs/password_input.rb +40 -0
  57. data/lib/formtastic/inputs/phone_input.rb +41 -0
  58. data/lib/formtastic/inputs/radio_input.rb +157 -0
  59. data/lib/formtastic/inputs/range_input.rb +119 -0
  60. data/lib/formtastic/inputs/search_input.rb +40 -0
  61. data/lib/formtastic/inputs/select_input.rb +210 -0
  62. data/lib/formtastic/inputs/string_input.rb +34 -0
  63. data/lib/formtastic/inputs/text_input.rb +47 -0
  64. data/lib/formtastic/inputs/time_input.rb +14 -0
  65. data/lib/formtastic/inputs/time_zone_input.rb +48 -0
  66. data/lib/formtastic/inputs/url_input.rb +40 -0
  67. data/lib/formtastic/localized_string.rb +105 -0
  68. data/lib/formtastic/railtie.rb +5 -7
  69. data/lib/formtastic/semantic_form_builder.rb +11 -0
  70. data/lib/formtastic/util.rb +6 -19
  71. data/lib/formtastic/version.rb +3 -0
  72. data/lib/generators/formtastic/install/install_generator.rb +28 -6
  73. data/lib/generators/templates/_form.html.erb +10 -4
  74. data/lib/generators/templates/_form.html.haml +8 -4
  75. data/lib/generators/templates/formtastic.rb +25 -32
  76. data/lib/locale/en.yml +1 -0
  77. data/lib/tasks/verify_rcov.rb +44 -0
  78. data/sample/basic_inputs.html +182 -0
  79. data/sample/config.ru +69 -0
  80. data/sample/index.html +14 -0
  81. data/spec/builder/custom_builder_spec.rb +109 -0
  82. data/spec/builder/error_proc_spec.rb +27 -0
  83. data/spec/builder/errors_spec.rb +193 -0
  84. data/spec/builder/semantic_fields_for_spec.rb +88 -0
  85. data/spec/helpers/buttons_helper_spec.rb +150 -0
  86. data/spec/helpers/commit_button_helper_spec.rb +470 -0
  87. data/spec/helpers/form_helper_spec.rb +135 -0
  88. data/spec/helpers/input_helper_spec.rb +837 -0
  89. data/spec/helpers/inputs_helper_spec.rb +562 -0
  90. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  91. data/spec/i18n_spec.rb +199 -0
  92. data/spec/inputs/boolean_input_spec.rb +184 -0
  93. data/spec/inputs/check_boxes_input_spec.rb +375 -0
  94. data/spec/inputs/country_input_spec.rb +133 -0
  95. data/spec/inputs/custom_input_spec.rb +52 -0
  96. data/spec/inputs/date_input_spec.rb +110 -0
  97. data/spec/inputs/datetime_input_spec.rb +115 -0
  98. data/spec/inputs/email_input_spec.rb +55 -0
  99. data/spec/inputs/file_input_spec.rb +59 -0
  100. data/spec/inputs/hidden_input_spec.rb +120 -0
  101. data/spec/inputs/include_blank_spec.rb +70 -0
  102. data/spec/inputs/label_spec.rb +104 -0
  103. data/spec/inputs/number_input_spec.rb +487 -0
  104. data/spec/inputs/numeric_input_spec.rb +41 -0
  105. data/spec/inputs/password_input_spec.rb +69 -0
  106. data/spec/inputs/phone_input_spec.rb +55 -0
  107. data/spec/inputs/placeholder_spec.rb +71 -0
  108. data/spec/inputs/radio_input_spec.rb +234 -0
  109. data/spec/inputs/range_input_spec.rb +477 -0
  110. data/spec/inputs/search_input_spec.rb +55 -0
  111. data/spec/inputs/select_input_spec.rb +545 -0
  112. data/spec/inputs/string_input_spec.rb +163 -0
  113. data/spec/inputs/text_input_spec.rb +158 -0
  114. data/spec/inputs/time_input_spec.rb +155 -0
  115. data/spec/inputs/time_zone_input_spec.rb +87 -0
  116. data/spec/inputs/url_input_spec.rb +55 -0
  117. data/spec/spec.opts +2 -0
  118. data/spec/spec_helper.rb +361 -0
  119. data/spec/support/custom_macros.rb +656 -0
  120. data/spec/support/deferred_garbage_collection.rb +21 -0
  121. data/spec/support/deprecation.rb +6 -0
  122. data/spec/support/test_environment.rb +30 -0
  123. metadata +306 -88
  124. data/generators/form/USAGE +0 -16
  125. data/generators/form/form_generator.rb +0 -111
  126. data/generators/formtastic/formtastic_generator.rb +0 -26
  127. data/init.rb +0 -5
  128. data/lib/formtastic/layout_helper.rb +0 -12
  129. data/lib/generators/formtastic/form/form_generator.rb +0 -84
  130. data/lib/generators/templates/formtastic.css +0 -145
  131. data/lib/generators/templates/formtastic_changes.css +0 -14
  132. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  133. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  134. data/rails/init.rb +0 -2
@@ -0,0 +1,392 @@
1
+ module Formtastic
2
+ module Helpers
3
+
4
+ # {#inputs} is used to wrap a series of form items in a `<fieldset>` and `<ol>`, with each item
5
+ # in the list containing the markup representing a single {#input}.
6
+ #
7
+ # {#inputs} is usually called with a block containing a series of {#input} methods:
8
+ #
9
+ # <%= semantic_form_for @post do |f| %>
10
+ # <%= f.inputs do %>
11
+ # <%= f.input :title %>
12
+ # <%= f.input :body %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # The HTML output will be something like:
17
+ #
18
+ # <form class="formtastic" method="post" action="...">
19
+ # <fieldset>
20
+ # <ol>
21
+ # <li class="string required" id="post_title_input">
22
+ # ...
23
+ # </li>
24
+ # <li class="text required" id="post_body_input">
25
+ # ...
26
+ # </li>
27
+ # </ol>
28
+ # </fieldset>
29
+ # </form>
30
+ #
31
+ # It's important to note that the `semantic_form_for` and {#inputs} blocks wrap the
32
+ # standard Rails `form_for` helper and FormBuilder, so you have full access to every standard
33
+ # Rails form helper, with any HTML markup and ERB syntax, allowing you to "break free" from
34
+ # Formtastic when it doesn't suit:
35
+ #
36
+ # <%= semantic_form_for @post do |f| %>
37
+ # <%= f.inputs do %>
38
+ # <%= f.input :title %>
39
+ # <li>
40
+ # <%= f.text_area :body %>
41
+ # <li>
42
+ # <% end %>
43
+ # <% end %>
44
+ #
45
+ # @see Formtastic::Helpers::InputHelper#input
46
+ module InputsHelper
47
+ include Formtastic::Helpers::FieldsetWrapper
48
+ include Formtastic::LocalizedString
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
+ # {#inputs} creates an input fieldset and ol tag wrapping for use around a set of inputs. It can be
55
+ # called either with a block (in which you can do the usual Rails form stuff, HTML, ERB, etc),
56
+ # or with a list of fields (accepting all default arguments and options). These two examples
57
+ # are functionally equivalent:
58
+ #
59
+ # # With a block:
60
+ # <% semantic_form_for @post do |form| %>
61
+ # <% f.inputs do %>
62
+ # <%= f.input :title %>
63
+ # <%= f.input :body %>
64
+ # <% end %>
65
+ # <% end %>
66
+ #
67
+ # # With a list of fields (short hand syntax):
68
+ # <% semantic_form_for @post do |form| %>
69
+ # <%= f.inputs :title, :body %>
70
+ # <% end %>
71
+ #
72
+ # # Output:
73
+ # <form ...>
74
+ # <fieldset class="inputs">
75
+ # <ol>
76
+ # <li class="string">...</li>
77
+ # <li class="text">...</li>
78
+ # </ol>
79
+ # </fieldset>
80
+ # </form>
81
+ #
82
+ # **Quick Forms**
83
+ #
84
+ # Quick, scaffolding-style forms can be easily rendered for rapid early development if called
85
+ # without a block or a field list. In the case an input is rendered for **most** columns in
86
+ # the model's database table (like Rails' scaffolding) plus inputs for some model associations.
87
+ #
88
+ # In this case, all inputs are rendered with default options and arguments. You'll want more
89
+ # control than this in a production application, but it's a great way to get started, then
90
+ # come back later to customise the form with a field list or a block of inputs. Example:
91
+ #
92
+ # <% semantic_form_for @post do |form| %>
93
+ # <%= f.inputs %>
94
+ # <% end %>
95
+ #
96
+ # **Nested Attributes**
97
+ #
98
+ # One of the most complicated parts of Rails forms comes when nesting the inputs for
99
+ # attrinbutes on associated models. Formtastic can take the pain away for many (but not all)
100
+ # situations.
101
+ #
102
+ # Given the following models:
103
+ #
104
+ # # Models
105
+ # class User < ActiveRecord::Base
106
+ # has_one :profile
107
+ # accepts_nested_attributes_for :profile
108
+ # end
109
+ # class Profile < ActiveRecord::Base
110
+ # belongs_to :user
111
+ # end
112
+ #
113
+ # Formtastic provides a helper called `semantic_fields_for`, which wraps around Rails' built-in
114
+ # `fields_for` helper for backwards compatibility with previous versions of Formtastic, and for
115
+ # a consistent method naming API. The following examples are functionally equivalent:
116
+ #
117
+ # <% semantic_form_for @user do |form| %>
118
+ # <%= f.inputs :name, :email %>
119
+ #
120
+ # <% f.semantic_fields_for :profile do |profile| %>
121
+ # <% profile.inputs do %>
122
+ # <%= profile.input :biography %>
123
+ # <%= profile.input :twitter_name %>
124
+ # <% end %>
125
+ # <% end %>
126
+ # <% end %>
127
+ #
128
+ # <% semantic_form_for @user do |form| %>
129
+ # <%= f.inputs :name, :email %>
130
+ #
131
+ # <% f.fields_for :profile do |profile| %>
132
+ # <% profile.inputs do %>
133
+ # <%= profile.input :biography %>
134
+ # <%= profile.input :twitter_name %>
135
+ # <% end %>
136
+ # <% end %>
137
+ # <% end %>
138
+ #
139
+ # {#inputs} also provides a DSL similar to `fields_for` / `semantic_fields_for` to reduce the
140
+ # lines of code a little:
141
+ #
142
+ # <% semantic_form_for @user do |f| %>
143
+ # <%= f.inputs :name, :email %>
144
+ #
145
+ # <% f.inputs :for => :profile do %>
146
+ # <%= profile.input :biography %>
147
+ # <%= profile.input :twitter_name %>
148
+ # <%= profile.input :shoe_size %>
149
+ # <% end %>
150
+ # <% end %>
151
+ #
152
+ # The `:for` option also works with short hand syntax:
153
+ #
154
+ # <% semantic_form_for @post do |form| %>
155
+ # <%= f.inputs :name, :email %>
156
+ # <%= f.inputs :biography, :twitter_name, :shoe_size, :for => :profile %>
157
+ # <% end %>
158
+ #
159
+ # {#inputs} will always create a new `<fieldset>` wrapping, so only use it when it makes sense
160
+ # in the document structure and semantics (using `semantic_fields_for` otherwise).
161
+ #
162
+ # All options except `:name`, `:title` and `:for` will be passed down to the fieldset as HTML
163
+ # attributes (id, class, style, etc).
164
+ #
165
+ # When nesting `inputs()` inside another `inputs()` block, the nested content will
166
+ # automatically be wrapped in an `<li>` tag to preserve the HTML validity (a `<fieldset>`
167
+ # cannot be a direct descendant of an `<ol>`.
168
+ #
169
+ #
170
+ # @option *args :for [Symbol, ActiveModel, Array]
171
+ # The contents of this option is passed down to Rails' fields_for() helper, so it accepts the same values.
172
+ #
173
+ # @option *args :name [String]
174
+ # The optional name passed into the `<legend>` tag within the fieldset (alias of `:title`)
175
+ #
176
+ # @option *args :title [String]
177
+ # The optional name passed into the `<legend>` tag within the fieldset (alias of `:name`)
178
+ #
179
+ #
180
+ # @example Quick form: Render a scaffold-like set of inputs for automatically guessed attributes and simple associations on the model, with all default arguments and options
181
+ # <% semantic_form_for @post do |form| %>
182
+ # <%= f.inputs %>
183
+ # <% end %>
184
+ #
185
+ # @example Short hand: Render inputs for a named set of attributes and simple associations on the model, with all default arguments and options
186
+ # <% semantic_form_for @post do |form| %>
187
+ # <%= f.inputs, :title, :body, :user, :categories %>
188
+ # <% end %>
189
+ #
190
+ # @example Block: Render inputs for attributes and simple associations with full control over arguments and options
191
+ # <% semantic_form_for @post do |form| %>
192
+ # <%= f.inputs do %>
193
+ # <%= f.input :title ... %>
194
+ # <%= f.input :body ... %>
195
+ # <%= f.input :user ... %>
196
+ # <%= f.input :categories ... %>
197
+ # <% end %>
198
+ # <% end %>
199
+ #
200
+ # @example Multiple blocks: Render inputs in multiple fieldsets
201
+ # <% semantic_form_for @post do |form| %>
202
+ # <%= f.inputs do %>
203
+ # <%= f.input :title ... %>
204
+ # <%= f.input :body ... %>
205
+ # <% end %>
206
+ # <%= f.inputs do %>
207
+ # <%= f.input :user ... %>
208
+ # <%= f.input :categories ... %>
209
+ # <% end %>
210
+ # <% end %>
211
+ #
212
+ # @example Provide text for the `<legend>` to name a fieldset (with a block)
213
+ # <% semantic_form_for @post do |form| %>
214
+ # <%= f.inputs :name => 'Write something:' do %>
215
+ # <%= f.input :title ... %>
216
+ # <%= f.input :body ... %>
217
+ # <% end %>
218
+ # <%= f.inputs do :name => 'Advanced options:' do %>
219
+ # <%= f.input :user ... %>
220
+ # <%= f.input :categories ... %>
221
+ # <% end %>
222
+ # <% end %>
223
+ #
224
+ # @example Provide text for the `<legend>` to name a fieldset (with short hand)
225
+ # <% semantic_form_for @post do |form| %>
226
+ # <%= f.inputs :title, :body, :name => 'Write something:'%>
227
+ # <%= f.inputs :user, :cateogies, :name => 'Advanced options:' %>
228
+ # <% end %>
229
+ #
230
+ # @example Inputs for nested attributes (don't forget `accepts_nested_attributes_for` in your model, see Rails' `fields_for` documentation)
231
+ # <% semantic_form_for @user do |form| %>
232
+ # <%= f.inputs do %>
233
+ # <%= f.input :name ... %>
234
+ # <%= f.input :email ... %>
235
+ # <% end %>
236
+ # <%= f.inputs :for => :profile do |profile| %>
237
+ # <%= profile.input :user ... %>
238
+ # <%= profile.input :categories ... %>
239
+ # <% end %>
240
+ # <% end %>
241
+ #
242
+ # @example Inputs for nested record (don't forget `accepts_nested_attributes_for` in your model, see Rails' `fields_for` documentation)
243
+ # <% semantic_form_for @user do |form| %>
244
+ # <%= f.inputs do %>
245
+ # <%= f.input :name ... %>
246
+ # <%= f.input :email ... %>
247
+ # <% end %>
248
+ # <%= f.inputs :for => @user.profile do |profile| %>
249
+ # <%= profile.input :user ... %>
250
+ # <%= profile.input :categories ... %>
251
+ # <% end %>
252
+ # <% end %>
253
+ #
254
+ # @example Inputs for nested record with a different name (don't forget `accepts_nested_attributes_for` in your model, see Rails' `fields_for` documentation)
255
+ # <% semantic_form_for @user do |form| %>
256
+ # <%= f.inputs do %>
257
+ # <%= f.input :name ... %>
258
+ # <%= f.input :email ... %>
259
+ # <% end %>
260
+ # <%= f.inputs :for => [:user_profile, @user.profile] do |profile| %>
261
+ # <%= profile.input :user ... %>
262
+ # <%= profile.input :categories ... %>
263
+ # <% end %>
264
+ # <% end %>
265
+ #
266
+ # @example Nesting {#inputs} blocks requires an extra `<li>` tag for valid markup
267
+ # <% semantic_form_for @user do |form| %>
268
+ # <%= f.inputs do %>
269
+ # <%= f.input :name ... %>
270
+ # <%= f.input :email ... %>
271
+ # <li>
272
+ # <%= f.inputs :for => [:user_profile, @user.profile] do |profile| %>
273
+ # <%= profile.input :user ... %>
274
+ # <%= profile.input :categories ... %>
275
+ # <% end %>
276
+ # </li>
277
+ # <% end %>
278
+ # <% end %>
279
+ def inputs(*args, &block)
280
+ wrap_it = @already_in_an_inputs_block ? true : false
281
+ @already_in_an_inputs_block = true
282
+
283
+ title = field_set_title_from_args(*args)
284
+ html_options = args.extract_options!
285
+ html_options[:class] ||= "inputs"
286
+ html_options[:name] = title
287
+
288
+ out = begin
289
+ if html_options[:for] # Nested form
290
+ inputs_for_nested_attributes(*(args << html_options), &block)
291
+ elsif block_given?
292
+ field_set_and_list_wrapping(*(args << html_options), &block)
293
+ else
294
+ legend = args.shift if args.first.is_a?(::String)
295
+ args = default_columns_for_object if @object && args.empty?
296
+ contents = fieldset_contents_from_column_list(args)
297
+ args.unshift(legend) if legend.present?
298
+ field_set_and_list_wrapping(*((args << html_options) << contents))
299
+ end
300
+ end
301
+
302
+ out = template.content_tag(:li, out, :class => "input") if wrap_it
303
+ @already_in_an_inputs_block = false
304
+ out
305
+ end
306
+
307
+ protected
308
+
309
+ def default_columns_for_object
310
+ cols = association_columns(:belongs_to)
311
+ cols += content_columns
312
+ cols -= SKIPPED_COLUMNS
313
+ cols.compact
314
+ end
315
+
316
+ def fieldset_contents_from_column_list(columns)
317
+ columns.collect do |method|
318
+ if @object && (@object.class.reflect_on_association(method.to_sym) && @object.class.reflect_on_association(method.to_sym).options[:polymorphic] == true)
319
+ 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.")
320
+ end
321
+ input(method.to_sym)
322
+ end
323
+ end
324
+
325
+ # Collects association columns (relation columns) for the current form object class. Skips
326
+ # polymorphic associations because we can't guess which class to use for an automatically
327
+ # generated input.
328
+ def association_columns(*by_associations) #:nodoc:
329
+ if @object.present? && @object.class.respond_to?(:reflections)
330
+ @object.class.reflections.collect do |name, association_reflection|
331
+ if by_associations.present?
332
+ if by_associations.include?(association_reflection.macro) && association_reflection.options[:polymorphic] != true
333
+ name
334
+ end
335
+ else
336
+ name
337
+ end
338
+ end.compact
339
+ else
340
+ []
341
+ end
342
+ end
343
+
344
+ # Collects content columns (non-relation columns) for the current form object class.
345
+ def content_columns #:nodoc:
346
+ model_name.constantize.content_columns.collect { |c| c.name.to_sym }.compact rescue []
347
+ end
348
+
349
+ # Deals with :for option when it's supplied to inputs methods. Additional
350
+ # options to be passed down to :for should be supplied using :for_options
351
+ # key.
352
+ #
353
+ # It should raise an error if a block with arity zero is given.
354
+ def inputs_for_nested_attributes(*args, &block) #:nodoc:
355
+ options = args.extract_options!
356
+ args << options.merge!(:parent => { :builder => self, :for => options[:for] })
357
+
358
+ fields_for_block = if block_given?
359
+ raise ArgumentError, 'You gave :for option with a block to inputs method, ' <<
360
+ 'but the block does not accept any argument.' if block.arity <= 0
361
+ lambda do |f|
362
+ contents = f.inputs(*args){ block.call(f) }
363
+ template.concat(contents)
364
+ end
365
+ else
366
+ lambda do |f|
367
+ contents = f.inputs(*args)
368
+ template.concat(contents)
369
+ end
370
+ end
371
+
372
+ fields_for_args = [options.delete(:for), options.delete(:for_options) || {}].flatten
373
+ fields_for(*fields_for_args, &fields_for_block)
374
+ end
375
+
376
+ def field_set_title_from_args(*args) #:nodoc:
377
+ options = args.extract_options!
378
+ options[:name] ||= options.delete(:title)
379
+ title = options[:name]
380
+
381
+ if title.blank?
382
+ valid_name_classes = [::String, ::Symbol]
383
+ valid_name_classes.delete(::Symbol) if !block_given? && (args.first.is_a?(::Symbol) && content_columns.include?(args.first))
384
+ title = args.shift if valid_name_classes.any? { |valid_name_class| args.first.is_a?(valid_name_class) }
385
+ end
386
+ title = localized_string(title, title, :title) if title.is_a?(::Symbol)
387
+ title
388
+ end
389
+
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,33 @@
1
+ module Formtastic
2
+ module Helpers
3
+ # @private
4
+ module Reflection
5
+ # If an association method is passed in (f.input :author) try to find the
6
+ # reflection object.
7
+ def reflection_for(method) #:nodoc:
8
+ @object.class.reflect_on_association(method) if @object.class.respond_to?(:reflect_on_association)
9
+ end
10
+
11
+ def association_macro_for_method(method) #:nodoc:
12
+ reflection = reflection_for(method)
13
+ reflection.macro if reflection
14
+ end
15
+
16
+ def association_primary_key_for_method(method) #:nodoc:
17
+ reflection = reflection_for(method)
18
+ if reflection
19
+ case association_macro_for_method(method)
20
+ when :has_and_belongs_to_many, :has_many, :references_and_referenced_in_many, :references_many
21
+ :"#{method.to_s.singularize}_ids"
22
+ else
23
+ return reflection.foreign_key.to_sym if reflection.respond_to?(:foreign_key)
24
+ return reflection.options[:foreign_key].to_sym unless reflection.options[:foreign_key].blank?
25
+ :"#{method}_id"
26
+ end
27
+ else
28
+ method.to_sym
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ module Formtastic
2
+ # Quick hack/shim for anything expecting the old SemanticFormHelper module.
3
+ # TODO remove from 2.0 with a helpful upgrade path/warning.
4
+ # @private
5
+ module SemanticFormHelper
6
+ include Formtastic::Helpers::FormHelper
7
+ @@builder = Formtastic::Helpers::FormHelper.builder
8
+ @@default_form_class = Formtastic::Helpers::FormHelper.default_form_class
9
+ mattr_accessor :builder, :default_form_class
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Formtastic
2
+ # @private
3
+ module HtmlAttributes
4
+
5
+ protected
6
+
7
+ def humanized_attribute_name(method)
8
+ if @object && @object.class.respond_to?(:human_attribute_name)
9
+ humanized_name = @object.class.human_attribute_name(method.to_s)
10
+ if humanized_name == method.to_s.send(:humanize)
11
+ method.to_s.send(label_str_method)
12
+ else
13
+ humanized_name
14
+ end
15
+ else
16
+ method.to_s.send(label_str_method)
17
+ end
18
+ end
19
+
20
+ end
21
+ end