Reputation: 11706
Assuming I have an existing app with the following models:
class User < ActiveRecord::Base
has_many :locations, :through => :location_users
end
class Location < ActiveRecord::Base
has_many :users, :through => :location_users
end
How do I go about converting this has_many to a has_one association like below, as far as migrations, trimming records of people with multiple locations, and anything else I missed? Are there any shortcuts to do this conversion?
class User < ActiveRecord::Base
belongs_to :location
end
class Location < ActiveRecord::Base
has_many :users
end
EDIT: User belongs to one and only one location
Upvotes: 0
Views: 1205
Reputation: 29349
No Shortcuts.
Write a migration to add location_id
to users
table
class AddLocationIdToUsers < ActiveRecord::Migration
def change
add_column :users, :location_id, :integer
end
end
And you can write another migration to populate the location_id for the existing users. For eg, if you want to populate the first location_id for the user in the locations_users table
class PopulateLocationIdOnUser < ActiveRecord::Migration
def up
#executing direct query to speed up the operation
execute("update users set location_id = (select location_id from locations_users where locations_users.user_id = users.id limit 1)")
end
def down
execute("update users set location_id = null")
end
end
And another migration to drop locations_users table
class DropLocationsUsersTable < ActiveRecord::Migration
def up
drop_table :locations_users
end
def down
create_table :locations_users do |t|
#columns
end
end
end
You can also have a single migration to do all the three steps too.
Upvotes: 1
Reputation: 1861
There isn't really an easy way around this. You're going to have to do a lot of manually work from my experience. This is how I went about it:
Write a migration to add user_id
to the locations table.
Run the migration
Add the has_one relation code. (like you have above)
class User < ActiveRecord::Base
has_one :location
end
class Location < ActiveRecord::Base
belongs_to :user
end
Either write a migrations to convert all the existing data over. (e.g. location.user = location.users.first
). But it might be better in this case to write a rake task because this will only happen once and it will need to relay on your has_many
relationship code to exist. So your migration would be invalid once you remove the has_many
code.
Run your rake task
Remove the has_many
code and join table.
After doing all that it should all work. Others might have a better way but this is how I did it.
Upvotes: 1