Jesus Rodriguez
Jesus Rodriguez

Reputation: 12018

Validate form called through another controller

Im writing a blog engine, So I have a post view (show.html.erb) that shows a post, comments list and a comments form.

I call the form this way:

<%= render :partial => 'comments/form', :locals => {:comment => @post.comments.new} %>

Im not sure if passing the comment that way is correct, but at least I get the post_id on the new comment.

This is my form (_form.html.erb on comments view):

<%= form_for comment, :action => "create" do |f| %>
    <% if comment.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being added:</h2>

          <ul>
            <% comment.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
          </ul>
        </div>
    <% end %>

  <%= f.hidden_field :post_id %>
  <p>
    <%= f.label :name %>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :email %>
    <%= f.text_field :email %>
  </p>
  <p>
    <%= f.label :url %>
    <%= f.text_field :url %>
  </p>
  <p>
    <%= f.label :content %>
    <%= f.text_area :content %>
  </p>
  <p class="no-border">
    <%= f.submit "Post", :class => "button" %>
  </p>
<% end %>

And this the action:

  def create
    @comment = Comment.new(params[:comment])

    respond_to do |format|
      if @comment.save
        format.html { redirect_to :back }
      else
        format.html { redirect_to :back }
      end
    end
  end

A bit verbose but I want to add more stuff.

I can add comments perfectly but I can't view validation errors.

I leave all blank (my model have validation stuff) and I see that the comment created in the create action have the errors and go to the else path.

But... The form doesn't show any errors.

I think that I have an object with the erorrs but when I redirect back, the object I pass to the form is a new one again and doesn't have the errors.

So, where is the problem?

EDIT: Extra stuff:

Im my show.html.erb I also have this (before the form):

<ol class="commentlist">
  <%= render @post.comments %>
</ol>

So, When in the show action I put the extra variable:

def show
  @post = Post.find(params[:id])
  @comment = @post.comments.new

It seems that the render wants to render the empty comment too and make an exception.

How to bypass that?

Upvotes: 1

Views: 699

Answers (1)

Carlos Ramirez III
Carlos Ramirez III

Reputation: 7434

When you redirect back, you are calling the PostsController#show action again which will reset all of the instance variables. If you wanted to save state after the failed CommentsController#create call, you would need to call render 'posts/show' instead of redirect :back which would reuse the instance variables which were declared in the current action

def create
   # assuming you have nested the comments routes underneath posts...
   @post = Post.find(params[:post_id])
   @comment = @post.comments.build(params[:comment])

   respond_to do |format|
      if @comment.save
         format.html { redirect_to :back }
      else
         format.html do
            # remember to declare any instance variables that PostsController#show requires
            # e.g. @post = ...
            render 'posts/show'
         end
      end
   end
end

You would also need to make sure that the partial uses @comment instead of creating a new comment each time

<%= render :partial => 'comments/form', :locals => {:comment => @comment } %>

And make sure the PostsController declares @comment

# e.g. inside PostsController
def show
   @post = Post.find(params[:id])
   @comment = Comment.new
end

The most important thing to remember is to make sure that the code inside the failed create call initializes all the instance variables that the PostsController#show action template requires otherwise you'll get errors.

Upvotes: 1

Related Questions