这是我经常遇到的一致性问题。
让我们考虑一个典型的论坛:
选择这两个选项的最佳做法是什么:
# Initialize @post on the User
def create
@post = current_user.posts.build(params[:post])
@post.topic_id = @topic.id
if @post.save
...
end
end
或者
# Initialize @post on the Topic
def create
@post = @topic.posts.build(params[:post])
@post.user_id = current_user.id
if @post.save
...
end
end
或者有更好的方法,考虑到在上面的例子中,@ post user_id
或topic_id
必须添加到attr_accesssible
(感觉hacky)?
答案 0 :(得分:3)
我设法找到的最干净的方法是使用CanCan:当你有一个规则can :create, Post, :user_id => user.id
并在控制器中添加load_resource
时,它会设置属性。
但它并不总是合适的。如果有一个通用的解决方案可以一次性初始化嵌套对象,那将会很不错。
更新。我想出了另一个选择:
@post = @topic.posts.where(user_id: current_user.id).build(params[:post])
一般来说,所有这些方法都会打破Law of Demeter。最好将其封装在模型的方法中,如下所示:
class Topic < ActiveRecord::Base
def new_post(params={}, author=nil)
posts.build(params).tap {|p| p.user = author}
end
end
然后在控制器中:
@post = @topic.new_post(params[:post], current_user)
答案 1 :(得分:2)
你永远不需要使用ID或attr_accessible。如果用户has_many
帖子和主题has_many
帖子比您可以做的那样
# Initialize @post on the User
def create
@post = current_user.posts.build(params[:post])
@post.topic = @topic #assuming you've gotten the topic from somewhere
if @post.save
...
end
end
从用户或主题构建起来确实没有太大区别,但对用户而言,从用户看起来更自然。
答案 2 :(得分:0)
我更喜欢
@post = @topic.posts.build(params[:post])
@post.user = current_user
虽然我没有看到其他方法有任何问题,但通过主题构建帖子对我来说更自然(因为帖子主要显示在其主题的上下文中而不是用户本身)。