开发者

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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜