Best practice for creating a model with two belongs_to associations?
This is a consistency problem that I'm running into often.
Let's consider a typical Forum:
- User can create Posts
- Posts belong to a Topic
- Posts also belong to the User that created them
What's the best practice for choosing between these two op开发者_运维问答tions:
# Initialize @post on the User
def create
@post = current_user.posts.build(params[:post])
@post.topic_id = @topic.id
if @post.save
...
end
end
Or
# Initialize @post on the Topic
def create
@post = @topic.posts.build(params[:post])
@post.user_id = current_user.id
if @post.save
...
end
end
Or is there a better way, considering that, in the above examples, either @post's user_id
or topic_id
would have to be added to attr_accesssible
(feels hacky)?
The cleanest approach I managed to find is using CanCan: when having a rule can :create, Post, :user_id => user.id
and adding load_resource
in your controller it will set the attributes.
But it is not always suitable. It would be nice to have some generic solution to initalize nested objects in one shot.
Update. I've come up with another option:
@post = @topic.posts.where(user_id: current_user.id).build(params[:post])
Generally speaking, all of these approaches break the Law of Demeter. It would be better to encapsulate in a method of the model, like this:
class Topic < ActiveRecord::Base
def new_post(params={}, author=nil)
posts.build(params).tap {|p| p.user = author}
end
end
Then in controller:
@post = @topic.new_post(params[:post], current_user)
You never need to monkey with IDs or attr_accessible. If a User has_many
Posts and a Topic has_many
Posts than you can do
# 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
There really isn't a big difference in building from the user or from the topic, but going from the user seems more natural to me.
I prefer
@post = @topic.posts.build(params[:post])
@post.user = current_user
Although I dont see any problem with the other approach, building post via topic make more natural to me(as posts are mostly displayed in the context of its topic rather than the user itself).
精彩评论