It appears that Rails will define the association while the application is initializing, and then continue to use that definition until the application exits. This will cause an undesired association if the value "Active" cannot be found in the associated model. I tripped across this behavior during a migration. A run through the log revealed that Rails has defined the association as "milestone_status_id = nil" because the entry for "Active" had not been added to the database while the migration process was initializing. The plan, of course, is to add "Active" to the table during the migration, but by then it is too late.

Furthermore, the :conditions portion of this association will throw "table not found" errors if attempting to rebuild the database via migrations. The rake db:migrate process will exit during environment initialization.

The knee-jerk solution is to use "MilestoneStatus.find_or_create_by_name("Active"). While that would solve the erroneous "milestone_status_id = nil" definition, it doesn't address the "table not found" error when migrating and the MilestoneStatus table hasn't been created yet.

Here's a brutish version of the association that handles the "table not found" error, but it also highlights the need to reload/reinitialize the association:

If the MilestoneStatus table has been created, Rails adds/finds "Active" to the table and generates the correct association definition. Otherwise the :conditions line is defined as "milestone_status_id = 0" (which should never return a matching record).

I know the script/console has the handy reload! command, but that seems to have a bug correctly processing includes from the lib folder. And it's also not available from inside a running application or migration.

Of course, I could be going about this all wrong. If that's the case, please tell me!

Re: Reload/reinitialize a model association?

Interestingly, this issue appears to have resolved itself. The associations now work correctly, even when migrating from an empty database.

I will test further, both in Windows and OS X, and attempt to recreate the issue. For what it's worth, the issue occured while I was running the app in server mode in one process while executing the rake migration in another process.

The problem will still occur if you add the needed data earlier in the migration. And it doesn't matter if the data is added in an earlier migration file - if the data wasn't there when "rake db:migrate" was called, the project.milestones association will refer to a nil value.

Using the same Project class that was defined earlier in this post, here's the updated migration code that redefines the Project model:

Redefining the model during a migration will override any associations, validations, constants, or custom methods that you've added to the model's definition. Actually, redefining the model at any point during an application's run will override all the wonderfullness that you've added to the model's definition. This would be disastrous if used in your main application code. But in a migration, it can be handy and does not affect the model when in development or production.

Some of you might balk at this "solution" - understandably so! This is a "use with caution" technique. There might be later migrations that use some of the model's extra methods, and the migration will crash because those methods will be undefined. (eg "project.milestones.create!(:name => 'milestone test')") But the Rails folks discourage using associations during migrations for this very reason. They acknowledge that from-scratch migrations can fail because models/associations may have changed since the failing migration was written.

Re: Reload/reinitialize a model association?

To add to this, migrations are not ideal for inserting or updating data. If you need to have some sort of default data, such as an admin user, add it to db/seeds.rb file using the active record methods, like Model.create!(). The idea is when you deploy, you run your migrations, then you can run the rake db:seed command if necessary. Your migrations shouldn't depend on data that's not there. Migrations are purely meant to setup the data model of the application.