17

What is the preferred way to display validation error messages using form_for in Rails 4?

<%= form_for @post do |f| %>
  ...
<% end %>
Kyle Decot
  • 20,715
  • 39
  • 142
  • 263

4 Answers4

34

This is how I am displaying them for my form object called @location:

<% if @location.errors.any? %>
<ul>
  <% @location.errors.full_messages.each do |msg| %>
    <li><%= msg %></li>
  <% end %>
</ul>
<% end %>

Note: put the above code after the <%= form_for @location do |f| %> line

Danny
  • 3,982
  • 1
  • 34
  • 42
17

My preferred way of doing this and keeping the code simple and DRY, is the following:

Create a new helper inside of application_helper.rb

# Displays object errors
def form_errors_for(object=nil)
  render('shared/form_errors', object: object) unless object.blank?
end

Create a new shared partial in shared/_form_errors.html.erb

<% content_for :form_errors do %>
  <p>
    <%= pluralize(object.errors.count, "error") %> prevented the form from being saved:
  </p>

  <ul>
    <% object.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

Edit your application.html.erb file to include the errors where you want them:

<%= yield :form_errors %>

Finally, place the helper at the start of each form:

<%= form_for(@model) do |f| %>
  <%= form_errors_for @model %>

  <%# ... form fields ... %>
<% end %>

This makes it extremely simple to manage and show your form errors across many forms.

Wes Foster
  • 8,770
  • 5
  • 42
  • 62
  • Thank you very much! In Rails 4.x its very important to create a folder called "shared" so the partial can be called correctly, otherwise you would get an ActionView::MissingTemplate error. – Enrique Diaz Jan 08 '16 at 11:05
  • In the example above, does <%= yield :form_errors %> replace the standard <%= yield %> or it is in addition to? What does adding :form_errors to yield do vs the standard yield? – user2012677 Jan 27 '16 at 15:25
  • No, it does not replace it. The standard yield has a completely different use as it renders the view in the layout. – Wes Foster Jan 27 '16 at 15:51
  • <%= yield :form_errors %> is equivalent to <%= content_for :form_errors %>, which may be easier to understand (it's just printing out the html you stored in that key previously) – nruth Feb 15 '16 at 22:33
  • 1
    nice job. saved me time. +1 – Yonk May 18 '16 at 13:03
10

Same as Rails 3 -- see f.error_messages in Rails 3.0 or http://railscasts.com/episodes/211-validations-in-rails-3 for many different possibilities.

My personal preference is to use simple_form and have it put the error next to the input.

Community
  • 1
  • 1
Jesse Wolgamott
  • 40,197
  • 4
  • 83
  • 109
1

I know this isn't exactly what was asked, but if you are using the simple_form gem, which I recommend, you can use f.error_notification which takes :message as an option.

= f.error_notification message: form_errors_for(your_object)

I use a method pretty similar to Wes's answer; form_errors_for inside application_helper.rb

def form_errors_for_base(object)
  if object.errors.messages[:base].present?
    object.errors.messages[:base].join(",\n") + "."
  else
    nil
  end
end
jlesse
  • 564
  • 5
  • 11