# Adds a few helpful methods to the standard form builder to implement Derek
# Featherston's suggestions for accessible forms, which can be found at
# http://simplyaccessible.org
class AccessibleFormBuilder < ActionView::Helpers::FormBuilder
# Returns a form input label for the given field.
#
# Options:
#
# :required:: Mark as a required field (default: +false+)
# :include_error_messages:: Display error messages related to this particular field (default: +true+)
#
# Examples:
#
<%= f.label :name, :required => true %>
# <%= f.text_field :name %>
#
# <%= f.label :company %>
# <%= f.text_field :company %>
#
# <%= f.label :state, :required => true, :value => 'State/Province' %>
# <%= f.text_field :state %>
def label(field, options = {}, html_options = {})
options = options.reverse_merge(:required => false, :include_error_messages => true)
value = options.delete(:value) || field.to_s.humanize
html_options.stringify_keys!
html_options['for'] ||= "#{@object_name}_#{field}"
if options[:required]
value = %Q(* #{value})
end
if options[:include_error_messages] and !@object.errors[field].blank?
# Include the error messages in the label
value += %( #{@object.errors[field].to_a.to_sentence})
# Add the 'error' class
html_options['class'] ||= ''
html_options['class'] += ' ' unless html_options['class'].blank?
html_options['class'] += 'error'
end
@template.content_tag :label, value, html_options
end
# The object's validation messages in readable, sentence form.
def validation_message
(@object.errors.on("base").to_a + formatted_attr_error_messages).to_sentence
end
private
def formatted_attr_error_messages
ordered_attr_error_messages.map do |(attr,msg)|
"" + @object.class.human_attribute_name(attr) + " " + msg
end
end
def ordered_attr_error_messages
@object.errors.collect {|attr,msg| [attr, msg]}.reject{|a| a[0] == "base"}.sort_by {|a| column_position_of_attribute(a[0].to_s) || ""}
end
def column_position_of_attribute(attribute)
@object.class.columns.map(&:name).index(attribute)
end
end
module ActionView #:nodoc:
module Helpers #:nodoc:
module FormHelper
# Same as +form_for+ but yields an AccessibleFormBuilder
def accessible_form_for(object_name, *args, &proc)
options = args.last.is_a?(Hash) ? args.pop : {}
options[:builder] = AccessibleFormBuilder
form_for(object_name, *(args << options), &proc)
end
# Same as +fields_for+ but yields an AccessibleFormBuilder
def accessible_fields_for(object_name, *args, &proc)
options = args.last.is_a?(Hash) ? args.pop : {}
options[:builder] = AccessibleFormBuilder
fields_for(object_name, *(args << options), &proc)
end
end
end
end