Luke Carrier

Rails 3.0, select tags and field_with_errors

Published 5 years ago

When doing my thing with GameGrid today, I decided to place emphasis on fields in forms which needed user attention. I ran into a shortcoming in the way Rails's form helpers treat <select> tags, though. I propose a workaround here.

Updated: you don't need to use <%= %> with the block now. This goes against "the Rails way".

Usually, when active record flags a field as failing validations, the handy Rails form helpers in action view will wrap a <div> with the field_with_errors class around it, enabling you to style these elements with some simple CSS rules. Unfortunately, this doesn't seem to extend to <select> tags, which get no highlighting at all.

Numerous fixes have been suggested, such as this old thread on StackOverflow, but since the functionality these rely upon has since been marked for deprecation and has been moved into the new dynamic_form gem they don't work without adding another gem to your Gemfile. This fix works for me, though.

You'll need to add this helper method to one of your files in /app/helpers. Since I use this frequently, I place it in application_helper.rb, but this may not be appropriate for your use case.

def field_with_errors(object, method, &block)
  if block_given?
    if object.errors[method].empty?
      concat capture(&block)
    else
      concat content_tag(:div, capture(&block), class: "field_with_errors")
    end
  end
end

All we're doing here is adding a method we can call from our view to encapsulate a select field within. The block method isn't something we need to worry about, since Rails will use the format of our view to identify the contents of the variable (the content between the method call and the next end statement, if you're using ERb).

So, a usage example:

<% field_with_errors @user, :date_of_birth do %>
  <%= f.date_select :date_of_birth %>
<% end %>

Obviously, the above is contained within by form block. Here, I've got my date_select, which is being used to provide the :date_of_birth of a @user.