Search code examples
ruby-on-railsrefactoringrails-migrations

Active record migrations and refactoring


I'm in the midst of a fairly steep bit of refactoring on my current project. Previous to reaching this crossroads I have two models that I came to realize are really the same model but with in a different state and I want to represent the system that way. As a result I have to take all the objects of the soon to be defunct model and move them into the other model and set the new status column correctly. The problem is simple code-wise, especially since the models are so similar as is.

The pain point for me is that I have to make these changes at some midpoint in my migration in both directions. The path from here to there will be sort of like:

add_column :model_ones, :status, :string

make_all_model_two_records_into_model_one_records()

drop_table :model_twos

Clearly the other direction is easy to define as well

create_table :model_twos do |t|
  ...
end

move_model_ones_with_status_x_into_model_twos_table

remove_column :model_ones, :status

This is a good but when I get to that magical moment that I remove ModelTwo.rb from my repo then the whole thing goes to pot. At that point I can't ever migrate from the ground up w/o reading that source. My reaction to that is to either write straight sql to move the data back and forth or to take that data conversion out of the migration. If I take it out, where the heck does it go? How do I ensure it happens at the right time when migrating?

And let's say I surmount that aspect of the problem and I can now migrate happily from zero to present. I can NEVER migrate down, right? Does this represent some moment in time where the concept of staged migrations is simply dead to me?

I suppose I could go back and massage the earlier migrations to convince the world that ModelTwo never existed at all, but the thought of violating the sanctity of existing migrations makes my skin crawl.

People have to be doing this sort of refactor with Rails already somewhere. It has to be feasible, right? I can't figure out how to do it.

Thanks in advance, jd


Solution

  • I would:

    1. Create a migration that adds the status column

    2. Run a rake task to move your data across

    3. Test all the data moved correctly

    4. Run another migration for removing the old table that isn't needed.

    Sometimes you are going to need to alter old migrations to ensure you can build development environments easily. I am not sure why you think it's such a problem. The migrations are there to help you, not some magic rule you should feel obliged to abide by.

    Sometimes you can get too hung up on best practice and forget that it's very hard to have "best practice rules" that apply to every situation. They are good as a guide but ultimately best practice is doing what is best for your project.