0

I would have thought that if a table relationship is set up properly in a model file, ActiveRecord would take care of updating and inserting the data into the junction table.

Is this not so?

For example, I have a dvd.rb model that looks like this:

  has_and_belongs_to_many :dvd_producer

The junction table is named accordingly dvd_producers_dvds (I know, silly name but that's what ActiveRecord expects).

Basically, when I insert a new producer into the dvd_producers table via:

DvdProducer.create(producer: producer)

I would expect that ActiveRecord inserts the equivalent data (producer_id, dvd_id) into the junction table automatically.

Maybe I need to use the new_producer.save method instead of create?

Or is this just a pipe dream?

kakubei
  • 5,321
  • 4
  • 44
  • 66

2 Answers2

1

Are you ever appending a dvd to the dvd_producer? I'm not even seeing you create a dvd, something like.

producer = DvdProducer.create(producer: producer)
producer.dvds << Dvd.create(title: title)

Should get you what you want.

Krustal
  • 518
  • 1
  • 4
  • 12
  • Not always. Sometimes I just need to insert producer and the data into the junction table because the DVD already exists. Is there no way of doing it then? – kakubei Nov 19 '12 at 09:36
  • What if I also have other relatinships like Director ane Writer. How could that be accomplished in like your example above? – kakubei Nov 20 '12 at 09:29
  • Ok, this works if I edit it a bit. Instead of creating a new record for dvd I can do `dvd.dvd_producer << producer`. I'm marking your poast as the answer since it led me to the correct case. Thanks – kakubei Nov 22 '12 at 15:32
1

The full answer is that if you need to insert data into a junction table but are not creating one of the other objects you can use an existing one.

So, to insert data into a junction table for an object you alreday have:

dvd = Dvd.find(:id)
producer  = Producer.where(producer: 'some guy').first_or_create
dvd.producer << producer

Of course this also works if you are ceating the objects as pointed out by Krustal above.

Use << to add data to a junction table and use = with the object as an array to replace data:

dvd.producer = [producer]

What's nice about this is that it works for a many to one relationship (one where you have an ID as a foreign key in the other table, like dvd.sound_id) as well with a slight change, use a = instead of <<:

dvd = Dvd.find(:id)
sound = Sound.where(sound: 'Dolby').first_or_create
dvd.sound = sound

Also, I am now addicted to first_or_create which I never knew existed. This is a wonderful method that saves you from having to first search for a record and create it if it doesn't exist. I can't believe I didn't know about this. Use it, it's great.

kakubei
  • 5,321
  • 4
  • 44
  • 66