【问题标题】:Association between post, user, and comment on Ruby on RailsRuby on Rails 上的帖子、用户和评论之间的关联
【发布时间】:2022-11-09 23:38:55
【问题描述】:

我正在尝试学习 Ruby on Rails,但我有点陷入联想。 我的项目是用三个表创建一个简单的博客。用户、帖子和评论。

据我了解,在将几个表与外键关联后,rails 会自动找到 user_id 和 post_id。但是每次我尝试构建 cmets 时,user_id 都是 nil。

这是我的模型:

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

这是我尝试创建评论时的屏幕截图:

如您所见,post_id 不是 nil,但 user_id 是 nil。

我尝试手动输入用户 ID,它按预期工作。但我不知道如何使用自动用户 ID 和 post_id 创建评论。

【问题讨论】:

  • 您能在此处添加有问题的comments_controller 代码吗?
  • 啊,对不起,这个练习需要用控制台来解决。
  • 你可以试试这个comment = post.comments.build(user_id: user.id)。参考答案

标签: ruby-on-rails ruby database activerecord


【解决方案1】:

据我了解,在将几个表与外键关联后,rails 会自动找到 user_id 和 post_id。但是每次我尝试构建 cmets 时,user_id 都是 nil。

这种假设是没有道理的。 Rails 不会自动分配您的关联 - 它甚至应该如何知道您要将评论与哪个用户/帖子关联?

通常,您构建它的方式是拥有一个nested route

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

这将创建路由 /posts/:post_id/comments 以便我们知道用户想要评论哪个帖子 - 然后您将调整您的表单,使其发布到嵌套路由:

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

获取评论的用户通常可以通过您的身份验证系统从会话中获取 - 在此示例中,来自 Devise 的 authenticate_user! 回调将对用户进行身份验证,否则如果没有用户登录,则重定向到登录。

然后,您只需从请求正文(来自表单)和会话中的用户分配白名单参数:

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 'comments/show', 
        status: :unprocessable_entity,
        notice: 'Could not create comment'
    end
  end

  private

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

这通常是 Rails 初学者在“Blorgh”教程中最挣扎的部分,因为它介绍了“嵌入”在另一个资源中的资源及其视图和几个高级概念。如果你还没有读过我真的会推荐Getting Started With Rails Guide

【讨论】:

    【解决方案2】:

    您可以如下创建一个 cmets:

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

    希望这会帮助你。

    【讨论】:

    • 感谢您的回答。虽然我想问一些事情。帖子可以将 user.id 传递给评论,所以我不需要创建 user = User.find 2?
    • 你可以使用post.user_id
    猜你喜欢
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 2023-03-02
    • 2019-02-20
    • 2013-06-08
    相关资源
    最近更新 更多