Class: RPH::FormAssistant::FormBuilder

Inherits:
ActionView::Helpers::FormBuilder
  • Object
show all
Defined in:
lib/form_assistant/form_builder.rb

Overview

FormAssistant::FormBuilder

* provides several convenient helpers (see helpers.rb) and
  an infrastructure to easily add your own
* method_missing hook to wrap content "on the fly"
* optional: automatically attach labels to field helpers
* optional: format fields using partials (extremely extensible)

Usage:

<% form_for @project, :builder => RPH::FormAssistant::FormBuilder do |form| %>
  // fancy form stuff
<% end %>

- or -

<% form_assistant_for @project do |form| %>
  // fancy form stuff
<% end %>

- or -

# in config/intializers/form_assistant.rb
ActionView::Base.default_form_builder = RPH::FormAssistant::FormBuilder

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.ignore_errorsObject

Returns the value of attribute ignore_errors.



45
46
47
# File 'lib/form_assistant/form_builder.rb', line 45

def ignore_errors
  @ignore_errors
end

.ignore_labelsObject

Returns the value of attribute ignore_labels.



44
45
46
# File 'lib/form_assistant/form_builder.rb', line 44

def ignore_labels
  @ignore_labels
end

.ignore_templatesObject

Returns the value of attribute ignore_templates.



43
44
45
# File 'lib/form_assistant/form_builder.rb', line 43

def ignore_templates
  @ignore_templates
end

.template_root(full_path = false) ⇒ Object

sets the root directory where templates will be searched note: the template root should be nested within the configured view path (which defaults to app/views)



71
72
73
# File 'lib/form_assistant/form_builder.rb', line 71

def template_root
  @template_root
end

Instance Attribute Details

#fallback_templateObject

used if no other template is available



36
37
38
# File 'lib/form_assistant/form_builder.rb', line 36

def fallback_template
  @fallback_template
end

Class Method Details

.assist(helper_name) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/form_assistant/form_builder.rb', line 204

def self.assist(helper_name)
  define_method(helper_name) do |field, *args|
    options          = (helper_name == 'check_box' ? args.shift : args.extract_options!) || {}
    label_options    = extract_options_for_label(field, options)
    template_options = extract_options_for_template(helper_name, options)
    extra_locals     = options.delete(:locals) || {}
    
    # build out the label element (if desired)
    label = label_options[:label] === false ? nil : self.label(field, label_options.delete(:text), label_options)

    # grab the tip, if any
    tip = options.delete(:tip)
    
    # is the field required?
    required = !!options.delete(:required)
    
    # ensure that we don't have any custom options pass through
    field_options = options.except(:label, :template, :tip, :required)
    
    # call the original render for the element
    super_args = helper_name == 'check_box' ? args.unshift(field_options) : args.push(field_options)
    element = super(field, *super_args)
    
    return element if template_options[:template] === false
    
    # return the helper with an optional label if templates are not to be used
    return render_element(element, field, helper_name, options, label_options[:label] === false) if self.class.ignore_templates
    
    # render the partial template from the desired template root
    render_partial_for(element, field, label, tip, template_options[:template], helper_name, required, extra_locals, args)
  end
end

.view_pathObject



60
61
62
63
64
65
66
# File 'lib/form_assistant/form_builder.rb', line 60

def view_path
  if Rails.configuration.respond_to?(:view_path)
    return Rails.configuration.view_path
  else
    return Rails.configuration.paths['app/views'].first
  end
end

Instance Method Details

#column_type(field) ⇒ Object



313
314
315
# File 'lib/form_assistant/form_builder.rb', line 313

def column_type(field)
  object.class.columns_hash[field.to_s].type rescue :string
end

#fields_for_with_form_assistant(record_or_name_or_array, *args, &proc) ⇒ Object

since #fields_for() doesn’t inherit the builder from form_for, we need to provide a means to set the builder automatically (works with nesting, too)

Usage: simply call #fields_for() on the builder object

<% form_assistant_for @project do |form| %>
  <%= form.text_field :title %>
  <% form.fields_for :tasks do |task_fields| %>
    <%= task_fields.text_field :name %>
  <% end %>
<% end %>


328
329
330
331
332
# File 'lib/form_assistant/form_builder.rb', line 328

def fields_for_with_form_assistant(record_or_name_or_array, *args, &proc)
  options = args.extract_options!
  # hand control over to the original #fields_for()
  fields_for_without_form_assistant(record_or_name_or_array, *(args << options.merge!(:builder => self.class)), &proc)
end

#input(field, *args) ⇒ Object



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/form_assistant/form_builder.rb', line 290

def input(field, *args)
  helper_name = case column_type(field)
    when :string
      field.to_s.include?('password') ? :password_field : :text_field
    when :text                      ; :text_area
    when :integer, :float, :decimal ; :text_field
    when :date                      ; :date_select
    when :datetime, :timestamp      ; :datetime_select
    when :time                      ; :time_select
    when :boolean                   ; :check_box
    else                            ; :text_field
  end
  
  send(helper_name, field, *args)
end

#inputs(*args) ⇒ Object



306
307
308
309
310
311
# File 'lib/form_assistant/form_builder.rb', line 306

def inputs(*args)
  options = args.extract_options!
  args.flatten.map do |field|
    input(field, options.dup)
  end.join('')
end

#partial(name, options = {}) ⇒ Object

Renders a partial, passing the form object as a local variable named ‘form’ <%= form.partial ‘shared/new’, :locals => { :whatever => @whatever } %>



284
285
286
287
288
# File 'lib/form_assistant/form_builder.rb', line 284

def partial(name, options={})
  (options[:locals] ||= {}).update :form => self
  options.update :partial => name
  @template.render options
end

#widget(*args, &block) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/form_assistant/form_builder.rb', line 257

def widget(*args, &block)
  options          = args.extract_options!
  fields           = args.shift || nil 
  field            = Array === fields ? fields.first : fields
  
  label_options    = extract_options_for_label(field, options)
  template_options = extract_options_for_template(self.fallback_template, options)
  label            = label_options[:label] === false ? nil : self.label(field, label_options.delete(:text), label_options)
  tip              = options.delete(:tip)
  locals           = options.delete(:locals)
  required         = !!options.delete(:required)

  if block_given?
    element = without_assistance do
      @template.capture(&block)
    end  
  else
    element = nil
  end    
  
  partial = render_partial_for(element, fields, label, tip, template_options[:template], 'widget', required, locals, args)
  RPH::FormAssistant::Rules.binding_required? ? @template.concat(partial, block.binding) : @template.concat(partial)
end

#without_assistance(options = {}, &block) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/form_assistant/form_builder.rb', line 243

def without_assistance(options={}, &block)
  # TODO - allow options to only turn off templates and/or labels
  ignore_labels, ignore_templates = self.class.ignore_labels, self.class.ignore_templates
 
  begin
    self.class.ignore_labels, self.class.ignore_templates = true, true
    result = yield
  ensure  
    self.class.ignore_labels, self.class.ignore_templates = ignore_labels, ignore_templates
  end  

  result
end