Using Models in Rails Migrations
Every now and then one is tempted to use models in rails migrations. This ingenious idea, however, turns out to be a pitfall since the life cycle of the code (model in this case) does not necessarily match that of the migrations. An example is given by Rails Guide showing how to create a local model within the migration to avoid such conflicts.
Another example would be renaming a models name (e.g. from class Item < ActiveRecord::Base
to class Product < ActiveRecord::Base
) and its corresponding table. This would break all the previous migrations utilizing that model. For example following migration would break:
class SomeMigration < ActiveRecord::Migration
method def
items = Item.all
...
end
end
Note that at this point the table items
already exists (since the new migration, which changes its name has naturally a bigger timestamp and is to be run after this migration) and using pure SQL (or respective DB DSL) using execute
(as some may propose) can save all such migrations from breaking:
class SomeMigration < ActiveRecord::Migration
method def
execute << -SQL
...
SELECT "items".* FROM "items"
...
SQL
end
end
This, however, creates a new problem:
- Switching to another DB (e.g. MySQL to PostgreSQL) demands rewriting all migrations including such codes. In other words the system is not DB agnostic anymore
- The convenient Active Record Query Interface (e.g.
ActiveRecord.find
)cannot be used anymore.
The best solution (that I have found up to now) is to create a generic model in the migration and make it access a specific table:
class SomeMigration < ActiveRecord::Migration
class GenericModel < ActiveRecord::Base
self.table_name = 'items'
end
method def
GenericModel.find ...
...
end
end
This way we can conserve the DB agnostic feature of RoR and enjoy the rich query interface without fearing future modifications to the model.
Disclaimer: This solution is a modified version of "How to use models in your migrations (without killing kittens)"