views:

1496

answers:

2

How do you edit the attributes of a join model when using accepts_nested_attributes_for?

I have 3 models: Topics and Articles joined by Linkers

class Topic < ActiveRecord::Base
  has_many :linkers
  has_many :articles, :through => :linkers, :foreign_key => :article_id
  accepts_nested_attributes_for :articles
end
class Article < ActiveRecord::Base
  has_many :linkers
  has_many :topics, :through => :linkers, :foreign_key => :topic_id
end
class Linker < ActiveRecord::Base
  #this is the join model, has extra attributes like "relevance"
  belongs_to :argument
  belongs_to :question
end

So when I build the article in the "new" action of the topics controller...

@topic.articles.build

...and make the nested form in topics/new.html.erb...

<% form_for(@topic) do |topic_form| %>
  ...fields...
  <% topic_form.fields_for :articles do |article_form| %>
    ...fields...

...Rails automatically creates the linker, which is great. Now for my question: My Linker model also has attributes that I want to be able to change via the "new topic" form. But the linker that Rails automatically creates has nil values for all its attributes except topic_id and article_id. How can I put fields for those other linker attributes into the "new topic" form so they don't come out nil?

+4  A: 

14 days later - Figured out the answer. Hopefully my next question will get some response. The trick was:

@topic.linkers.build.build_article

That builds the linkers, then builds the article for each linker. So, in the models:
topic.rb needs "accepts_nested_attributes for :linkers"
linker.rb needs "accepts_nested_attributes for :articles"

Then in the form:

<% form_for(@topic) do |topic_form| %>
  ...fields...
  <% topic_form.fields_for :linkers do |linker_form| %>
    ...linker fields...
    <% linker_form.fields_for :article do |article_form| %>
      ...article fields...
Arcolye
Let me know if this was helpful
Arcolye
Rails 3 update: the form_for and field_for need <%= %> instead of <% %> if you're using Rails 3.
Arcolye
A: 

I was just looking to do the same sort of thing! I've got two models:

Songs and Performances and they are joined by PlayedSongs.

But I've got additional fields besides song_id and performance_id on the PlayedSongs. One of which is "play_order" because the songs need to be displayed in the order they were played live (I'm working on a site to catalog live performances) and I couldn't figure out how to do it automagically...somehow having Rails auto-fill the played_order field with a loop starting at 1 and adding 1 for each additional song added to the performance.

This is a big help (I hope) toward making it a bit easier...right now I've got a separate action setup with a separate view that users must go to and manually enter the play_order after adding the songs to the show...this might allow me to bring that up one level and have it right on the page when they're first adding the songs.

I know this isn't helping you at all and for that I apologize, I just wanted to thank you for posting this after you figured it out.

I have a question though. Did this:

@topic.linkers.build.build_article

Replace

@topic.articles.build

In your New action then? Or are both lines still needed? And are you calling both

accepts_nested_attributes_for :article
accepts_nested_attributes_for :linker

on the topic model? Or just the line for :linker? If just :linker, is it because Rails is smart enough to know that Articles are tied to Linkers with the HMT relationship and therefore grants you access to that model as well?

klyrish
I just edited my answer to answer your question about accepts_nested_attributes_for.And, @topic.linkers.build.build_article replaces @topic.articles.build
Arcolye
So sorry it took so long to get back to you. Thank you for your help and for updating your code to reflect the answer to my question! Much appreciated :D
klyrish