Guys,
I’ve run across an interesting scenario with my migrations, and I hope
you might share some insight.
Let’s say I have 3 migrations and two Models (Person and Car):
001_initial_schema.rb
002_data_load.rb
003_add_car_association.rb
The first creates the initial schema…the second loads default data
using model objects of Person to do so, and the third creates a new
table, “cars”, and modifies the “persons” table to create a :has_one
relationship of Person[1]->[1]Car.
Let’s also say I want all Persons to have at least one car, so I change
my Person model to have:
def after_initialize
self.car = Car.new unless self.car
end
Now, what happens, is that when I issue a “rake migrate” on my intial
database
When I start from scratch (new database) and do a rake migrate, my data
load fails because it uses the model class Person, yet Person’s code now
has an after_initialize that expects the Car association to be present.
Because Car isn’t created until migration 003, I’m essentially up the
creek. rake throwns an InvalidStatement exception.
Has anyone found a decent way of handling these scenarios?
Thanks!
John
Thanks!
John
I prefer to keep my migrations free of my models for this very reason.
I’ll create temp models if I need to do basic queries, however.
class MyMigration < Migration
class Article < AR::Base
end
def self.up
end
def self.down
end
end
This essentially makes the model’s name MyMigration::Article, and
won’t clash with your app’s Article model or any other migrations’
Article models.
disclaimer: I haven’t actually tried this. However, I ran into this
issue on my Mephisto blogging tool and created temp models like
TempArticle. Someone had a question on the Rails-Core ML and led me
to this idea. I’ll try it next.
http://techno-weenie.net/svn/projects/mephisto/trunk/db/migrate/
–
Rick O.
http://techno-weenie.net
I’ve run across an interesting scenario with my migrations, and I hope
you might share some insight.
…
Has anyone found a decent way of handling these scenarios?
http://rails.techno-weenie.net/tip/2006/2/23/safely_using_models_in_migrations
Rick O. wrote:
def self.down
end
end
This essentially makes the model’s name MyMigration::Article, and
won’t clash with your app’s Article model or any other migrations’
Article models.
disclaimer: I haven’t actually tried this.
Having googled a bit, and seen your conversation on the rails-core list,
I did try it. It works. Very nicely
It’s a situation that I’m surprised doesn’t come up more often. Changes
to models breaking old migrations must be quite a common occurrence,
both because of lifecycle callbacks and because of relationship changes.
The rules of thumb I’ve come up with are:
- Always use local models in migrations (as above). An alternative
would be a patch to AR that exposed create_without_callbacks, but that
was more complex than I wanted to get in to, and wouldn’t cover
everything.
- Never rely on dynamic associations, always use foo[:bar_id] = qux[:id]
rather than foo.bar = qux.
I’ve found that following those rules allows changes to model code while
also letting your app bootstrap itself in a single rake migrate pass.