【问题标题】:A model which belongs to more than one other model simultaneously一个模型同时属于多个其他模型
【发布时间】:2016-03-01 11:00:32
【问题描述】:

具有以下关联:

class User < ActiveRecord::Base
  has_many :posts
  has_many :comments
end

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
end

我可以在控制器中做这样的事情:

@comment = current_user.comments.new(comment_params)
@comment.user

但要访问关联的Post,我需要手动设置它的父级:

@comment.post = Post.find params[:post_id]

当创建一个新的Comment 时,有没有更好的方法来做到这一点?

【问题讨论】:

  • 你的资源是嵌套的吗?看起来他们是。
  • 不,他们还没有。
  • 你能提供你的架构供用户发帖和评论吗?
  • belongs_to 方法仅应在此类包含外键时使用。那么你的Comment 模型中有user_idpost_id 吗?
  • @AzatGataoulline 是的,我有。

标签: ruby-on-rails ruby activerecord associations


【解决方案1】:

我会使用嵌套资源

resources :posts do
  resources :comments
end

然后我将通过帖子构建评论并合并到当前用户的 id 中,这样您就不需要隐藏字段,这些字段显然可以被操纵。

class CommentsController
  def new
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new
  end

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new(comment_params)
  end

  private

  def comment_params
    params.require(:comment).permit(:content).merge({ user_id: current_user.id })
  end

end

您只需要在创建评论时合并当前用户,这样您就可以拥有一个在创建时调用的私有 comment_creation_params 方法

def comment_params
  params.require(:comment).permit(:content)
end

def comment_creation_params
  comment_params.merge({ user_id: current_user.id })
end

【讨论】:

  • 我认为在帖子的显示页面上显示cmets,以及发布它们的人更多。什么创建回调?你的意思是创建动作?这就是我在底部所说的。然后在创建操作中使用@comment = @post.comments.new(comment_creation_params)
  • 这只是解决了这种特殊情况,但又增加了一个问题:我无法通过@comment.user 访问用户,而且通常我无法从belongs_to :user 添加的功能中受益
  • @Sajjad 何乐而不为,只需添加belongs_to :user,然后您就可以添加@comment.user
  • 对不起,我在 rails 控制台尝试@comment.post 时收到了相关的帖子。但在控制器中我得到零。还 comment_params 包含 :body:comment_id 但我仍然在 @comment.save 之前或之后得到 nil
  • @Sajjad,这对我来说似乎是一个单独的问题。你能用你的控制器代码发布一个单独的问题吗?
【解决方案2】:

所以,主要的想法只是摆脱Post.find(params[:post_id])

如果我是你,我会在 comment_params 中明确插入 post_id

def comment_params
  params.require(:comment).permit(:text).merge(post_id: params[:post_id])
end

为了确保帖子存在,我会在评论中添加验证:

class Comment
  validates :post, presence: true
  #...
end

如果您不想将评论与帖子相关联,您可以跳过此验证或编写自定义验证

validate do
  errors.add(:post_id, 'There is no post') unless Post.find(post_id).present?
end

其中一个答案建议使用嵌套资源的解决方案,这是另一种解决方法。

【讨论】:

  • 我的代码的问题是,我不能使用@comment.post 访问相关的帖子,也不能将CommentPost 关联起来
  • @Sajjad,事实上,当评论属于帖子时,为什么不希望评论与帖子相关联?
  • @Sajjad,我已经编辑了我的答案。根本不需要添加验证,comment_params 可以解决问题。
  • 对不起,如果我表达的意思很糟糕。我的意思是将Comment 的实例与Post 的实例关联起来没有任何问题
【解决方案3】:

如果您希望 cmets 对象与 or 相关联,则可以使用多态关联。

http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

class User < ActiveRecord::Base
  has_many :posts
  has_many :comments, as: :commentable
end

class Posts < ActiveRecord::Base
  belongs_to :user
  has_many :comments, as: :commentable
end

您将无法使用@comment.post,但您可以使用@comment.commentable,这将是您的 Post 或 User 对象,具体取决于与该实例关联的对象。

【讨论】:

  • 在我的代码中,PostUser 都与 Comment 相关联。
  • 他希望它属于两者,据我所知有多个belongs_to,而不是一个或另一个。
  • @ABrowne,这不是关于用户的评论。这是关于用户发表的帖子的评论。这两个字段都是必需的
  • 我第一次阅读这篇文章时做出了错误的假设。我认为它的评论会针对用户或帖子,而不是 OP 的意思,正如您所说,这看起来像是对用户发表的帖子的评论。
猜你喜欢
  • 2016-04-09
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多