Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: How to Convert has_one to has_many association

Assuming

class Kid < ActiveRecord::Base
    has_one :friend
end

class Friend< ActiveRecord::Base
  belongs_to :kid
end

How can I change this to

class Kid < ActiveRecord::Base
    has_many :friends
end

class Friend< ActiveRecord::Base
  belongs_to :kid
end

Will appreciate your insight...

like image 838
macdev Avatar asked Dec 20 '22 12:12

macdev


2 Answers

Collection

The bottom line is that if you change your association to a has_many :x relationship, it creates a collection of the associative data; rather than a single object as with the single association

The difference here has no bearing on its implementation, but a lot of implications for how you use the association throughout your application. I'll explain both


Fix

Firstly, you are correct in that you can just change your has_one :friend to has_many :friends. You need to be careful to understand why this works:

enter image description here

ActiveRecord associations work by associating something called foreign_keys within your datatables. These are column references to the "primary key" (ID) of your parent class, allowing Rails / ActiveRecord to associate them

As long as you maintain the foreign_keys for all your Friend objects, you'll get the system working no problem.

--

Data

To expand on this idea, you must remember that as you create a has_many association, Rails / ActiveRecord is going to be pulling many records each time you reference the association.

This means that if you call @kind.friends, you will no longer receive a single object back. You'll receive all the objects from the datatable - which means you'll have to call a .each loop to manipulate / display them:

@kid = Kid.find 1
@kid.friends.each do |friend|
   friend.name
end

If after doing this changes you have problem calling the save method on the order.save telling you that it already exists, and it not allowing you to actually have many order records for one customer you might need to call orders.save(:validate=> false)

like image 124
Richard Peck Avatar answered Dec 30 '22 14:12

Richard Peck


You have answered the question. Just change it in model as you've shown.

like image 24
Andrey Deineko Avatar answered Dec 30 '22 15:12

Andrey Deineko