Hi all,
I have a application with a “calls” model that has many “trips”. Now I’ve shoehorned in a concept of recurring calls and trips into these models with a boolean flag. I want to correct this by abstracting out from these two models, two new models, “recurring_calls” and “recurring_trips”. Here is what I think I need to do:
- Create the “recurring_calls” and “recurring_trips” tables.
- Move and recurring calls and trips from the “calls” and “trips” tables to the new tables.
- Delete the recurring specific fields from the “calls” and “trips” tables.
- Move logic from call.rb and trip.rb into recurring_call.rb and recurring_trip.rb
My question is really concerning step 2. Is this something that can be achieved using ruby or do I need to write this in SQL? If I write this in SQL is it possible to preserve the associated records? i.e. if I move a call that has_many trips to a recurring_call can I keep that relation? I think I know how to achieve this in ruby however it seems the migration would then break if I dramatically change the call and trip models.
This is an app in production so preserving the data is top priority. However, these models have become too big and resistant to change. In the past I’ve left a lot of detail up to active record. if I do need to move these records using SQL how do I ensure the all the IDs are correctly assigned? Should I just copy these over seeing as they’re already unique?
Thanks.
So here’s what I ended up doing:
class RecurringCallsAndTrips < ActiveRecord::Migration
def up
create_table :recurring_calls do |t|
...
end
create_table :recurring_trips do |t|
...
end
add_indexes ...
# move calls into recurring_calls
columns = [ list of attributes ].join(", ")
execute " INSERT INTO recurring_calls (#{columns})
SELECT #{columns} FROM calls
WHERE recurring = true"
#move trips into recurring_trips
attributes = [ list of attributes ]
columns = attributes.join(", ")
trip_columns = attributes.map {|attr| "trips.#{attr}"}.join(", ")
execute " INSERT INTO recurring_trips (#{columns + ', recurring_call_id'})
SELECT #{trip_columns + ', trips.call_id'} FROM trips
INNER JOIN calls ON calls.id = trips.call_id
WHERE calls.recurring = true"
# Delete the recurring calls and trips from calls and trips table
execute " DELETE trips
FROM trips
INNER JOIN calls ON calls.id = trips.call_id
WHERE calls.recurring = true"
execute " DELETE FROM calls WHERE recurring = true"
# Remove the recurring specific fields
remove_columns ...
end
def down
add_columns ...
columns = [ list of attributes ].join(", ")
execute " INSERT INTO trips (#{columns + ', call_id'})
SELECT #{columns + ', recurring_call_id'} FROM recurring_trips"
columns = [ list of attributes ].join(", ")
execute " INSERT INTO calls (#{columns + ', recurring'})
SELECT #{columns + ', 1'} FROM recurring_calls"
remove_indexs ...
drop_table :recurring_trips
drop_table :recurring_calls
end
end
Just for completeness.