Home > OS >  Association between post, user, and comment on Ruby on Rails
Association between post, user, and comment on Ruby on Rails

Time:11-09

I'm trying to learn Ruby on Rails, an I'm kinda stuck with associaton. My project is to create a simple blog with three table. User, Post, and Comment.

In my understanding, after associationg several table with foreign key, rails would automatcily find user_id and post_id. But everytime I try to build comments, the user_id is nil.

Here's my model:

class User < ApplicationRecord
  has_many :posts
  has_many :comments
  
  validates :name, presence: true, length: { minimum: 5 }, uniqueness: true
  validates :password, presence: true, length: { minimum: 5 }
end
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: {minimum: 10}
end

class Comment < ApplicationRecord
  belongs_to :post
  belongs_to :user
  
  validates :body, presence: true
  validates :user_id, presence: true
  validates :post_id, presence: true
end

Here is the screenshot when I try to create a comment: enter image description here

As you can see, the post_id is not nil but the user_id is nil.

I try to input user_id manualy and it work as intended. But I can't find out how to create comment with automatic user_id and post_id.

CodePudding user response:

In my understanding, after associationg several table with foreign key, rails would automatcily find user_id and post_id. But everytime I try to build comments, the user_id is nil.

There is no truth to that assumption. Rails will not automatically assign your assocations - how should it even know what user/post you want to associate the comment with?

Typically the way you would construct this is to have a nested route:

resources :posts do
  resources :comments, 
   only: [:create]
   shallow: true
end

This creates the route /posts/:post_id/comments so that we know which post the user wants to comment on - you would then adjust your forms so that it posts to the nested route:

# app/views/comments/_form.html.erb
<%= form_with(model: [post, comment]) do |f| %>
  # ...
<% end %>
# app/views/comments/_form.html.erb
<%= render partial: 'comments/form', 
  post: @post,
  comment: @post.comments.new

Getting the user who's commenting would typically be done by getting it from the session through your authentication system - in this example the authenticate_user! callback from Devise would authenticate the user and otherwise redirect to the sign in if no user is signed in.

You then simply assign the whitelisted parameters from the request body (from the form) and the user from the session:

class CommentsController
  before_action :authenticate_user!
  
  # POST /posts/1/comments
  def create
    # This gets the post from our nested route
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new(comment_params) do |c| 
      c.user = current_user
    end

    if @comment.save
      redirect_to @post, 
        status: :created
        notice: 'Comment created'
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def comment_params
    params.require(:comment)
          .permit(:foo, :bar, :baz)
  end
end

This is typically the part that Rails beginners struggle the most with in "Blorgh" tutorials as it introduces a resource thats "embedded" in another resource and its views and several advanced concepts. If you haven't already I read it would really recommend the Getting Started With Rails Guide.

CodePudding user response:

you can create a comments as below:

user = User.find 2
post = user.posts.where(id: 2).first
comment = post.comments.build({comment_params}.merge(user_id: user.id))

Hope this will help you.

  • Related