10

Given

User:

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

Discussions:

class Discussion < ActiveRecord::Base
    belongs_to :user
    has_many :posts
end

Posts:

class Post < ActiveRecord::Base
    belongs_to :user
    belongs_to :discussion 
end

I am currently initializing Posts in the controller via

@post = current_user.posts.build(params[:post])

My question is, how do I set/save/edit the @post model such that the relationship between the post and the discussion is also set?

Cœur
  • 37,241
  • 25
  • 195
  • 267
James Pleasant
  • 707
  • 1
  • 6
  • 12

1 Answers1

13

Save and edit discussions along with post

Existing Discussion

To associate the post you're building with an existing discussion, just merge the id into the post params

@post = current_user.posts.build(
          params[:post].merge(
            :discussion_id => existing_discussion.id
        ) 

You will have to have a hidden input for discussion id in the form for @post so the association gets saved.


New Discussion

If you want to build a new discussion along with every post and manage its attributes via the form, use accepts_nested_attributes

class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :discussion
  accepts_nested_attributes_for :discussion
end

You then have to build the discussion in the controller with build_discussion after you built the post

@post.build_discussion

And in your form, you can include nested fields for discussions

form_for @post do |f|
  f.fields_for :discussion do |df|
    ...etc


This will create a discussion along with the post. For more on nested attributes, watch this excellent railscast


Better Relations

Furthermore, you can use the :through option of the has_many association for a more consistent relational setup:

class User < ActiveRecord::Base
  has_many :posts
  has_many :discussions, :through => :posts, :source => :discussion
end

class Discussion < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :discussion 
end

Like this, the relation of the user to the discussion is maintained only in the Post model, and not in two places.

Beat Richartz
  • 9,474
  • 1
  • 33
  • 50
  • Wow, that was a great read. Thanks for your time. I do have one question though. Every time the user starts a discussion they will have to have a post, however the reverse is not necessarily true. As in my case where a Discussion consists of many posts, would it be appropriate to flip what you said about posts and discussions such that the Discussions accepts nested attributes for posts, then do a @discussion.build_post, or is there some inconsistency that will come with that? – James Pleasant Jul 18 '12 at 14:51
  • You're welcome. And yes, if the relationship is User has many Discussions has many Posts, then you should reflect it that way in your code. – Beat Richartz Jul 18 '12 at 14:58
  • by the way... are you familiar with the belongs_to polymorphic: true element? – James Pleasant Jul 18 '12 at 15:07
  • Yeah, its up a bit of a different alley but still related. As with the prior code, discussions also has a belongs_to polymorphic: true. This is because a "Discussion" in my case is a general forum thread, and thus I would like to put it on other models. However the discussion would only be directly related to one of those at a time. In such a case would I still be fine using the accepts_nested_attributes_for and then building the discussion on those models? Or would you suggest another approach? – James Pleasant Jul 18 '12 at 15:18
  • [You may have to change some code if you want to use `accepts_nested_attributes_for` on the polymorphic association](http://stackoverflow.com/questions/3969025/accepts-nested-attributes-for-with-belongs-to-polymorphic), but it should work fine. Since there's no other approach to polymorphic associations than to use polymorphism :) – Beat Richartz Jul 18 '12 at 15:34
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14081/discussion-between-james-pleasant-and-beat-richartz) – James Pleasant Jul 18 '12 at 15:36
  • Do i have to make discussion_id attr_accessible in order to user this method? If that is the case, is there a way to do this without making it accessible? – Uri Klar Oct 16 '13 at 07:25