Mr eel
Error Display Helpers
The existing error helpers in Rails are pretty nice, but lack one major feature I was looking for. I wanted to have errors displayed for more than one model at a time. For example adding a schedule to a job when it is created in a CRM system.
So I knocked something together myself:
def error_messages(*keys)
errors = []
# Check the errors for each object specified
keys.each do |key|
object = instance_variable_get("@#{key}")
unless object.errors.empty?
object.errors.full_messages.collect { |msg| errors < < content_tag("li", msg) }
end
end
if errors.length > 0
content_tag("div",
content_tag("h2", "#{pluralize(errors.length, "error")} prohibited this form from being saved.") +
content_tag("p", "These are the problems with this form:") +
content_tag("ul", errors.each { |li| li }),
:id => 'errorMessage'
)
end
end
A couple of things to note about this helper. It’s based fairly closely on the existing helpers in Rails, but doesn’t allow you to customise the class names or ids used for the HTML elements, nor does it let you choose the heading. I’ll expand this in the future to make it more re-usable.
You can call it in your templates like so; < %= error_messages(:job, :schedule) %>. You can see I’m asking for the helper to display errors for the objects stored in the instance variables @job and @schedule.
One interesting thing I noticed is the method instance_variable_get(). It takes a key and returns a reference to an instance variable… obviously. Nice! Now I understand why Rails makes such heavy use of keys. The memory requirements are smaller and they can easily be used to reference instance variables if needed.
Comments
Jason Cartwright on November 9, 2005
Your code is good and I have it “working” in my application. However, I have a User and Address object, each with validation. I only directly call @new_user.save, and the @new_user.address object is saved internally. So I don’t seem to get any validation errors even when fields are left blank. Any suggestions?
Jason Cartwright on November 9, 2005
OK, I found the answer to my problem. You can call Class#valid? prior to saving and it will provide all the errors. So in my case I can write
if @new_user.valid? & @new_user.address.valid?
…
end
This has the added benefit of not committing the records to the database and creating a possibly invalid state across the objects.
Mr eel on November 9, 2005
That’s a good one! I should probably start using that myself.