views:

364

answers:

1

Hi guys,

Rails question. The default behavior for error validation is to fieldWithError-styled div around the input field like the following

<div class="type-text" id="pre_negotiation_value_div">
<label for="contract_budget_holder">Budget Holder</label>
<div class="fieldWithErrors">
<input id="contract_budget_holder"name="contract[budget_holder]" size="30" type="text" value="" />
</div>
</div>

What I am trying to accomplish is, to surround the label AND the input field with a classed div tag, so to look like the following:

<div class="type-text fieldWithErrors" id="pre_negotiation_value_div">
<label for="contract_budget_holder">Budget Holder</label>      
<input id="contract_budget_holder"name="contract[budget_holder]" size="30" type="text" value="" />      
</div>

Any ideas how to accomplish this? Can you hook up javascript into ActionView::Base.field_error_proc?

I am new to Rails, I apologize if this is super easy!

Thanks for your help.

Jonathan

+1  A: 

It's not super easy to do exactly what you want, but if you have ERB like this:

<div id="pre_negotiation_value_div" class="type-text">
  <%= f.label :name %>
  <%= f.text_field :name %>
</div>

You will get HTML like this:

<div id="pre_negotiation_value_div" class="type-text">
  <div class="fieldWithErrors"><label for="foo_name">Name</label></div>
  <div class="fieldWithErrors"><input id="foo_name" name="foo[name]" size="30" type="text" value="" />
</div>

Where both the label and the text_field will have the fieldWithErrors div around them. Depending on how you want to style it, that might be good enough. If it's not good enough, you'll have to do a custom helper like this:

class ActionView::Helpers::FormBuilder
  def labeled_input(method, options={}, &block)
    (options[:class] ||= "") << " fieldWithErrors" if @object.errors.on(method)
    ActionView::Helpers::InstanceTag.send(:alias_method, :original_error_wrapping, :error_wrapping)
    ActionView::Helpers::InstanceTag.send(:define_method, :error_wrapping,
      Proc.new {|html_tag, has_error| html_tag})
    @template.concat(@template.content_tag(:div, @template.capture(&block), options))
  ensure
    ActionView::Helpers::InstanceTag.send(:alias_method, :error_wrapping, :original_error_wrapping)
    ActionView::Helpers::InstanceTag.send(:remove_method, :original_error_wrapping)
  end
end

Put that in config/initializers/labeled_input.rb. It's a bunch Ruby meta-foo, but what it does is put the "fieldWithErrors" class on the outer div. It temporarily re-defines the error_wrapping method of InstanceTag so that the inner label and text_field tags don't have the "fieldWithErrors" div surrounding them. You use it in ERB like this:

<% f.labeled_input :name, :id => "pre_negotiation_value_div", :class => "type-text" do %>
  <%= f.label :name %>
  <%= f.text_field :name %>
<% end %>
pjb3
That worked man. Thanks!! I would have never thought of that.
Jonathan