Skip navigation

Active Record migrations can be useful to not just write migrations related to changes in database schema but to make one-time database insertions as well.

For example, making a new office location entry can be done using Active Record migrations.

class AddOfficeLocation < ActiveRecord::Migration
  def self.up
    OfficeLocation.new(:address_line1 => "Some blah", :address_line2 => "Some more blah", :city => "Coimbatore", capacity => 10)
  end

  def self.down
    office = OfficeLocation.find_by_city("Coimbatore")
    office.delete
  end
end

This is a relatively safe use of the power of ActiveRecord. The trouble starts when the temptation to put ActiveRecord models to better use kicks in.

class AddOfficeLocation < ActiveRecord::Migration
  def self.up
    office = OfficeLocation.my_custom_find_method_that_does_something()
    OfficeLocation.new(:address_line1 => office.address_line1, :address_line2 => office.address_line2, :city => "Coimbatore", capacity => 29)
  end

  def self.down
    office = OfficeLocation.find_by_city(&quot;Coimbatore&quot;)
    office.delete
  end
end

The danger here is that if the OfficeLocation model was to undergo some change during the course of which my_custom_find_method_that_does_something is deleted/changed/renamed, the effect of the method-change on the migration may end up never blowing up if the migrations are run incrementally.

If during the course of development, you are in the habit of doing a rake db:drop db:create before db:migrate, you are safe.

However, if you were to just run rake db:migrate, previously run migrations will never be run again and the effect of having removed/renamed my_custom_method_that_does_something will never be felt during development Finally, when the you deploy the code onto a new instance on production, the migrations break since the method will not be found.

The solution can be to always drop and create before migrating on development — as a habit. However a more robust solution will be to create a custom model within the migration and not depend on the model that the actual application uses.

class AddOfficeLocation < ActiveRecord::Migration
  def self.up
    office = OfficeLocationMig.my_custom_find_method_that_does_something()
    OfficeLocationMig.new(:address_line1 => office.address_line1, :address_line2 => office.address_line2, :city => "Coimbatore", capacity => 29)
  end

  def self.down
    office = OfficeLocation.find_by_city("Coimbatore")
    office.delete
  end
end

class OfficeLocationForMigration< ActiveRecord::Base

  set_table_name "officelocations"

  def self.my_custom_method_that_does_something
    #do something
    OfficeLocationForMigration.find_by_city("Coimbatore")
  end
end

Note: the use of the set_table_name method.

This way, the migration is coupled to a custom model and not the one exposed by the applicaiton.

Handy right?

Advertisements

2 Comments

  1. Nice tips. I have personally liked to keep data related changes outside of migrations. Those are onetime only tasks. Yes, it is not as “automatic” as migrations but you are better off not carrying the load of extinct model fields that may be long gone..

    Having said that, developers on team who are relatively new and haven’t had to maintain a project for a longer period of time don’t often see the benefit of keeping it as rake task and prefer the migration route.

    I will keep this link handy to point out next time.

    Nice job!

    • Thanks 🙂
      One off scripts become hard to maintain especially on dev boxes when you have been writing code for 6 months on a project.
      I am yet to try this out at an enterprise level. Will update the thread about the experience.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: