9
votes

I have a simple Video model in my rails app that has_many comments. I am displaying these comments on the video's show page. When I submit the form everything works fine; however, if there are validation errors on the Comment model, then my system blows up. If there are validation errors on the Comment model, I would simply like to render the video's show page again, with the validation error styling showing. How do I do this inside of my create action? Thanks a lot!

class CommentsController < ApplicationController
  def create
    @video = Video.find(params[:video_id])
    @comment = @video.comments.build(params[:comment])
    if @comment.save
      redirect_to @video, :notice => 'Thanks for posting your comments.'
    else
      render # what? What do I render in order to show the video page's show action with the validation error styling showing? Please help!
    end
  end
end
2

2 Answers

10
votes

To do this you'll have to render a template:

class CommentsController < ApplicationController
  def create
    @video = Video.find(params[:video_id])
    @comment = @video.comments.build(params[:comment])
    if @comment.save
      redirect_to @video, :notice => 'Thanks for posting your comments.'
    else
      render :template => 'videos/show'
    end
  end
end

Keep in mind that you'll have to declare any instance variables (like @video) inside of the CommentsController#create action as well though, because the VideosController#show action will not be run, the template will simply be rendered. For instance, if you have an @video_name variable in your VideosController#show action, you'll have to add the same @video_name instance variable to the CommentsController#create action.

10
votes

I have the same problem. I think your question is a duplicate of Rails validation over redirect (and also duplicated more recently by custom validations errors form controller inside other parent controller rails 3.1).

The problem with the above solution by Pan Thomakos is that if VideosController#show has more than a non-trivial amount of code in it then you would not be able to render from the videos/show template without violating the DRY rule. Here's a related discussion.

This post from Ryan Bates of Railscasts fame suggests that you could store @video in the flash to persist it across the redirect; however when I try to do that, it comes out the other side as an instance of the right class, but it doesn't have any of the superclasses you'd expect - most importantly ActiveRecord::Base. At first I thought maybe his advice was simply out of date (it was written in 2006). However, one of the answers to Rails validation over redirect written in October 2009 advocates the same approach, albeit via a custom clone_with_errors method which takes a shallow copy of the model instance in order to avoid issues with deeper objects. But even with that approach, any methods which rely on superclasses don't work. I'm guessing this is a consequence of the object being serialized into the flash and then deserialized out of it.

I found a page written in 2007 which advocates against storing model object instances in the session.

I also found a good argument in the formtastic google group pointing out that redirecting on validation failure is not the Rails Way, and probably a bad idea. But this still doesn't provide a good solution in the case where multiple controllers are involved. Perhaps Cells could be used to solve the DRY issue mentioned above.

Otherwise I guess the only answer is to stick with persisting simple data like object ids, error message strings, and so on.