0

I have a relationship between two models that is currently a many to many. I'd like to move it to a one to one relationship, because that's what all of the data has turned out to be.

Is there a seamless way to do this? Via a migration and model change combo? My models would be simple to just change as shown below:

Now

class App < ActiveRecord::Base
  has_and_belongs_to_many :owners
end

class Owner < ActiveRecord::Base
  has_and_belongs_to_many :apps
end

Changing to

class App < ActiveRecord::Base
  belongs_to :owner
end

class Owner < ActiveRecord::Base
  has_one :app
end

But how do I update the database to reflect these changes without losing any of the data I currently have?

Tom Prats
  • 7,364
  • 9
  • 47
  • 77

2 Answers2

1

Add an owner_id field to your apps table and then iterate through your apps_owners table and set the owner_id field in apps to the owner_id field in apps_owners for the apps record whose id is equal to app_id.

Assuming you're correct and there aren't multiple apps_owners entries for the same app_id following SQL should do it (not tested), although I'm not familiar with how to incorporate raw SQL into migrations:

update apps set owner_id=(select owner_id from apps_owners where apps.id = apps_owners.app_id)
Peter Alfvin
  • 28,599
  • 8
  • 68
  • 106
  • Couldn't you "migrate" back by doing a similar sql query? This one would be in the `up` with an `add_column` call and the other would be in the `down` – Tom Prats Dec 30 '13 at 23:04
  • I'm sure you're right. I've never thought of extending migrations to include raw SQL, but I'm sure it's possible. – Peter Alfvin Dec 30 '13 at 23:56
  • I think it actual turned out to be pretty simple, but I haven't tested it yet (yours works though!), but to migrate backwards from this you'd do `execute "INSERT INTO apps_owners (app_id, owner_id) SELECT id, owner_id FROM apps"` – Tom Prats Dec 31 '13 at 16:43
0

You won't be able to do this simply. The main problem is that has_and_belongs_to_many relationships use a tertiary database table (apps_owners in your case) to hold the relationship information.

After you create the appropriate migration to add owner_id to your App model, you'll need to create a rake task that reads the app_owner table and re-creates the relationships.

Donovan
  • 15,917
  • 4
  • 22
  • 34