2
votes

I have Comment belongs_to Post and Post has_many Comments, the comment model as following:

class Comment < ApplicationRecord
  belongs_to :post
  belongs_to :user
  validates :text, presence: true
end

The form which adds new comments is located in Posts show view, as following:

<%= form_with(model: [ @post, @post.comments.build ], local: true) do |form| %>
    <% if @comment.errors.any?%>
        <div id="error_explanation">
          <ul>
            <% @comment.errors.messages.values.each do |msg| %>
              <%msg.each do  |m| %>
                 <li><%= m %></li>
              <%end %>
             <% end %>
          </ul>
        </div>
    <% end %>
    <p>
       <%= form.text_area :text , {placeholder: true}%>
    </p>

    <p>
       <%= form.submit %>
    </p>
<% end %>

The Comments create action, as following:

class CommentsController < ApplicationController

def create
    @post = Post.find(params[:post_id])
    @comment = Comment.new(comment_params)
    @comment.post_id = params[:post_id]
    @comment.user_id = current_user.id
    if @comment.save
        redirect_to post_path(@post)
    else
        render 'posts/show'
    end
end



private
    def comment_params
      params.require(:comment).permit(:text)
    end
end

I need to render the posts/show page to show Comment validation errors, but the problem is I'm in CommentsController controller not PostsController so all objects used in pages/show view will be null.

How can I pass the @comment object to pages/show? I thought about using flash array, but I'm looking for more conventional way.

1

1 Answers

2
votes

Yep, rendering pages/show will just use the view template, but not the action, so anything you define in the pages#show controller action won't be available. @comment will be available though as you define that in the comments#create action. Without seeing the PostsController I don't know what else you're loading in the pages#show action - you could consider moving anything required in both to a method on ApplicationController, then calling from both places. Another option would be to change your commenting process to work via AJAX (remote: true instead of local: true on the form), and responding with JS designed to re-render just the comment form (you can move it into a partial used both in pages/show.html.erb and the comments#create response).

Couple of other notes on your code above - in comments#create, you can use:

@comment = @post.comments.new(comment_params)

to avoid needing to set the post_id on @comment manually.

For the form, I'd be tempted to setup a new comment in pages#show:

@comment = @post.comments.build

And then reference that in the form, it'll make it easier if you do re-use that between pages#show and comments#create:

<%= form_with(model: [ @post, @comment ], local: true) do |form| %>

Hope that helps!