Skip to content

Instantly share code, notes, and snippets.

@dwg
Created February 12, 2009 23:49
Show Gist options
  • Select an option

  • Save dwg/62953 to your computer and use it in GitHub Desktop.

Select an option

Save dwg/62953 to your computer and use it in GitHub Desktop.
Custom form builder that labels elements, handles errors and wraps in appropriate markup
# Drop the following in an initializer and enjoy consistency and less code when marking up forms.
# <% form_for @user do |f| %>
# <%= f.text_field :username %>
# <%= f.check_box :terms_accepted, :label=>'I accept the terms' %>
# <%= f.submit 'Save' %>
# <% end %>
# produces
# <form ...>
# <p>
# <label for="user_username">Username</label><br/>
# <input type="text" id="user_username" name="user[username]"/>
# </p>
# <p>
# <input type="checkbox" id="user_terms_accepted" name="user[terms_accepted"/>
# <label for="user_terms_accepted">I accept the terms</label>
# </p>
# <p>
# <input type="submit" id="user_submit" value="Save" name="commit"/>
# </p>
# </form>
# Will also append individual validation errors in a span following the erroring field (inside the p element)
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
non_breaking_helpers = %w(check_box radio_button)
breaking_helpers = field_helpers +
%w(select collection_select country_select + time_zone_select) +
%w(date_select time_select datetime_select) -
%w(fields_for submit hidden_field label) -
non_breaking_helpers
breaking_helpers.each do |helper|
src = <<-end_src
def #{helper}(method, *args, &block)
options = args.extract_options!
build_shell(method, options, block, true) do |options|
super method, *args << options
end
end
end_src
class_eval src, __FILE__, __LINE__
end
non_breaking_helpers.each do |helper|
src = <<-end_src
def #{helper}(method, *args, &block)
options = args.extract_options!
build_shell(method, options, block, false) do |options|
super method, *args << options
end
end
end_src
class_eval src, __FILE__, __LINE__
end
def submit *args
options = args.detect {|a| a.is_a?(Hash)}
builder_options = extract_builder_options(options)
@template.content_tag(:p, super, builder_options[:wrapper])
end
private
def build_shell method, options, block, breaking
builder_options = extract_builder_options(options)
errors = errors_for method
if errors
if options && options[:class]
options[:class] << ' fieldWithErrors'
elsif options
options[:class] = 'fieldWithErrors'
else
options = {:class=>'fieldWithErrors'}
end
end
element = yield options
label = make_label method, builder_options[:label]
if breaking
content = [label, (@template.tag(:br) if label), element, errors].compact
else
content = [element, label, errors].compact
end
if block
content = wrap(*content << @template.capture(&block) << builder_options[:wrapper])
@template.concat content, block.binding
else
wrap(*content << builder_options[:wrapper])
end
end
def make_label method, label_options
case label_options
when Hash
label(method, label_options.delete(:text), label_options)
when false
nil
else
label(method, label_options)
end
end
def extract_builder_options options
options ? {:label=>options.delete(:label), :wrapper=>options.delete(:wrapper)} : {}
end
def wrap *args
options = args.extract_options!
@template.content_tag(:p, args.join, options)
end
def errors_for method
if object && !object.errors.on(method).blank?
errors = object.errors.on(method)
errors = errors.is_a?(Array) ? errors.to_sentence : errors
@template.tag(:br) +
@template.content_tag(:span, errors, :class=>'fieldErrorMessage')
end
end
end
ActionView::Base.default_form_builder = LabellingFormBuilder
ActionView::Base.field_error_proc = lambda {|html_tag, instance| html_tag}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment