I have two models: Album and Track. Album has many tracks, and Track belongs to album.
I'd like to have the ability to create as many tracks as needed while creating the album, similailiy to railscasts episode 197. Unlike the railscasts episode, though, the Track form contains both a title and a description - both are required.
Right now, the form looks like this:
Create New Album
Name: [ ]
Track (remove link)
Name: [ ]
Description: [ ]
Track (remove link)
Name: [ ]
Description: [ ]
(add track link)
If I decide to submit the form blank, I get the following error messages on top of the form:
Description can't be blank
Title can't be blank
Title can't be blank
These error messages are not specific to the model, all located at the top of the page, and appear only once for each model (note that I left the fields for both blank and the error messages appear only once - not specific to which track).
To generate the initial track fields, I added the following line in the new action of my album_controller: 2.times { @album.tracks.build }
The gist of what my form looks like is this:
<% form_for @album do |f| %>
<%= f.error_messages %>
<%= f.label :title %><br />
<%= f.text_field :title %>
<% f.fields_for :tracks do |f, track| %>
<%= render :partial => 'tracks/fields', :locals => {:f => f} %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
I tried replacing the top <%= f.error_messages %>
with <%= error_messages_for @album %>
(to only display the messages for the album), and adding a <%= error_messages_for track %>
(to display the error messages specific to each track) - but this does not do the trick.
Does anybody know how to approach this?
Thanks!
If you want to separate error messages for parent and child object it can be a little complicated. Since when you save parent object it also validates child objects and it contains errors for children. So you can do something like this:
<% form_for @album do |f| %>
<%= custom_error_messages_helper(@album) %>
<%= f.label :title %><br />
<%= f.text_field :title %>
<% f.fields_for :tracks do |t| %>
<%= t.error_messages message => nil, :header_message => nil %>
<%= render :partial => 'tracks/fields', :locals => {:f => t} %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
Or you can put this line with t.error_messages
in 'tracks/fields'
partial (I renamed form builder object form f
to t
because it was confusing). It should display (at least it works for me) only errors for specific child object (so you can see what title error is for which object). Also keep in mind, that Rails will automaticaly add css class fieldWithErrors
to fields that contains errors, on example add to css:
.fieldWithErrors {
border: 1px solid red;
}
With errors for parent object it is more complicated since @album.errors
contains also errors for child objects. I didn't find any nice and simple way to remove some errors or to display only errors that are associatted with parent object, so my idea was to write custom helper to handle it:
def custom_error_messages_helper(album)
html = ""
html << '<div class="errors">'
album.errors.each_error do |attr, error|
if !(attr =~ /\./)
html << '<div class="error">'
html << error.full_message
html << '</div>'
end
end
html << '</div>'
end
It will skip all errors that are for attribute which name conatins '.' - so it should print all errors that are associated with the parent object. The only problem is with errors that are added to base - since they attr
value is base
and I'm not sure how are errors added to base to child object added to errors in parent object. Probably they attr
value is also base
so they will be printed in this helper. But it won't be problem if you don't use add_to_base
.