Slightly updated version of the “crud” app on downloads page
November 14, 2008 | Filed Under Rails
I wanted to note a detail about what happens when validation fails on model objects managed by a form; and how the form gets re-presented to the user.
The upshot of what I am about to describe is this: Make sure that all of the information the form needs is put back into the instance variables.
In the original version of the Student model, there were no validations - so a new Student would always get saved properly.
But let’s suppose that we add a validates_presence_of :last_name to the model. And let us suppose that the save fails because that field is left blank. Here’s what create looks like:
def create
@student = Student.new(params[:student])
if @student.save
redirect_to :action => :index
flash[:notice] = 'Student was successfully created.'
else
render :action => :new
end
end
Now here’s the problem: We’ve posted back to create, and because the save doesn’t work, we go to the else, which asks to render with the template associated with the new action. (Remember, incidentally, that this doesn’t mean execute the new action — it means only: Use the template associated with new.
However, one thing that is required for that form to work is for the @sections instance variable to be set up. This is used to get the available sections to show in the drop-down. I would urge you to add the validation and try to save a student with an empty last name. See the error? So, what we need to do is find all of those sections before rendering the template associated with new. In short, it should look like this:
def create
@student = Student.new(params[:student])
if @student.save
redirect_to :action => :index
flash[:notice] = 'Student was successfully created.'
else
@sections = Section.find(:all) # Important line!
render :action => :new
end
end
The previous version worked fine; but were we to have validations which result in the save failing, we would not be setting up the form properly.
I’ve uploaded a tweaked version of the “crud” app which you can get from the downloads page; both versions will work fine but I thought you should be aware of this important aspect of the form lifecycle.
Add New Comment
Viewing 7 Comments
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
__________________________________________
My erectie site.
Do you already have an account? Log in and claim this comment.
_______________________________
Online Degrees
Do you already have an account? Log in and claim this comment.
def create
@student = Student.new(params[:student])
if @student.save
redirect_to :action => :index
flash[:notice] = 'Student was successfully created.'
else
new #set up instance variables expected by the new view
render :action => :new
end
end
and, understanding that the reason we're doing this render instead of just redirecting to new is to preserve the value of @student, we could rewrite the second line of the new method as
@student ||= Student.new
to prevent overwriting the value, if it's there.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
This is probably a good case for a private method which both new and create would leverage -- that private method would load up @sections for the drop-down.
Do you already have an account? Log in and claim this comment.
Both solutions are problematic.
If you create a new set of @sections in create, then you're not DRY. If you do "@student ||= Student.new" and call the "new' method, then your "new" method isn't really create a NEW @student in all cases, so if you think that the method name should be explanatory, then you've given up on that. Which is fine if that's what you want. I have done it both ways myself.
In a more complicated strategy, you would "dry" up the entire new/create/edit/update cycle -- but that would require more trickery than we need right now. For pedagogical purposes -- and in this particular case -- I think the direct approach explains pretty clearly how when you get to that form, all of the data it needs must be in place.
Add New Comment