同时属于多个其他模型的模型

时间:2016-03-01 11:00:32

标签: ruby-on-rails ruby activerecord associations

具有以下关联:

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时,有更好的方法吗?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

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

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

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

答案 2 :(得分:-2)

如果你想让评论对象与其中任何一个相关联,那么多态关联就可以了。

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对象,具体取决于与该实例关联的对象。