# Avoiding reflection errors in migrations

**URL:** <https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481>\
**Category:** Rails\
**Created:** [July 3, 2007, 11:46pm UTC](https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481 "2007-07-03T23:46:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![andrew\_chase](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e5b9ba/32.png) [@andrew\_chase](https://www.ruby-forum.com/u/andrew_chase)\
**Post date:** [July 3, 2007, 11:46pm UTC](https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481/1 "2007-07-03T23:46:44Z")

</div>

I’ve hit an issue a couple times now with migrations that I’ve solved  
by hacking around, but now I’m interested in finding a more robust  
solution.

The problem comes when a migration contains some logic that requires  
the use of some class. However, within that class a new dependency has  
been added that relies on a migration that comes after the current  
one. Here’s a simple exmaple of what I mean:

— test\_class.rb  
class Test \< ActiveRecord::Base  
has\_many :foo  
def self.some\_method  
# do something useful  
end  
end

---- 002\_update\_test\_class.rb  
class UpdateTest \< ActiveRecord::Migration  
def self.up  
add\_column :tests, :my\_column, :integer  
Test.some\_method  
end  
end

— 003\_update\_test\_again.rb  
class UpdateTestAgain \< ActiveRecord::Migration  
def self.up  
create\_table(:foos) do  
# stuff  
end  
end  
end

Running all migrations would result in the following error:  
Mysql::Error: #42S02Table ‘my\_table.foos’ doesn’t exist: SHOW FIELDS  
FROM foos

So you see, the Test class is in an invalid state (it’s dependencies  
don’t exist yet) when I’m calling it from UpdateTest migration, and it  
will not be valid until the create\_table happens in the next  
migration.

Have other folks come across this? I’d be interested in hearing what  
solutions others have employed. One thing I’ve been thinking is that  
migrations could be separate out into two separate pieces: schema  
changes and content changes. So you’d have something like “up\_logic”  
as well as the standard “up” and after running through the "up"s for  
all migrations rake would then make a second pass running all the  
up\_logic methods. Stupid? Useful? Misguided?

Thanks,  
Andrew

---

<div class="post-metadata">

**Author:** ![andrew\_chase](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e5b9ba/32.png) [@andrew\_chase](https://www.ruby-forum.com/u/andrew_chase)\
**Post date:** [July 4, 2007, 3:23am UTC](https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481/2 "2007-07-04T03:23:58Z")

</div>

As a general rule, once I have a migration and the associated code  
working I commit my changes. Doing that, you could simply revert your  
working copy to the checkout required by the migration. Obviously that  
might not be what you’re looking for if you will be migrating back and  
forth often. If there’s another way, I’m not aware of it.

Out of curiosity, what are you doing with your model that’s required  
for the database to reach a correct state?

---

<div class="post-metadata">

**Author:** ![andrew\_chase](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e5b9ba/32.png) [@andrew\_chase](https://www.ruby-forum.com/u/andrew_chase)\
**Post date:** [July 4, 2007, 3:28pm UTC](https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481/3 "2007-07-04T15:28:08Z")

</div>

If you drastically change a model, the suggested approach with schema/  
logic separation might still fail since the logic might be not valid  
anymore. As for the actual solution for that specific problem, it all  
depends on which stage you have those migrations and what  
transformations do you do in them. For example, if Test.some\_method is  
harmless enough to run the second time, you can delete it from the  
original migration and add a new migration with the transformation  
code only right after UpdateTestAgain. If that is not the case, your  
options could go from creation of a special model containing the old  
model code (similar to the retired model described here  
[Revolution On Rails: Moving models to a different database](http://revolutiononrails.blogspot.com/2007/05/moving-models-to-different-database.html))  
or, if the original migration has been applied to production,  
replacing the code with straight SQL loading (see the migration  
consolidation here  
[Revolution On Rails: DB migrations with a twist](http://revolutiononrails.blogspot.com/2007/01/db-migrations-usage-at-rhg.html))

Hope it helps.

Val

---

<div class="post-metadata">

**Author:** ![andrew\_chase](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e5b9ba/32.png) [@andrew\_chase](https://www.ruby-forum.com/u/andrew_chase)\
**Post date:** [July 4, 2007, 4:22pm UTC](https://www.ruby-forum.com/t/avoiding-reflection-errors-in-migrations/108481/4 "2007-07-04T16:22:17Z")

</div>

On Jul 3, 2007, at 5:45 PM, andrew chase wrote:

> class Test \< ActiveRecord::Base  
> has\_many :foo  
> def self.some\_method  
> # do something useful  
> end  
> end
> 
> ---- 002\_update\_test\_class.rb  
> class UpdateTest \< ActiveRecord::Migration

# You need to add a copy of the Test model

# right here (yes, inside the migration class).

class Test \< ActiveRecord::Base  
def self.some\_method  
# do something useful  
end  
end

> ```
> # stuff
> 
> ```
> 
> don’t exist yet) when I’m calling it from UpdateTest migration, and it
> 
> Thanks,  
> Andrew

Doing the migration this way future-proofs it. You could migrate up  
and down by returning all your code to the same point in time, but  
the whole point of migrations is that you can drop a project into a  
clean environment, create the database, run a db:migrate, and be  
ready to go. I tend to put the minimal bits from the model class  
into the migration and then ONLY when the model class actually needs  
to be used. (Often this is to initialize the newly added table/  
column.) You might also need to call Model.reset\_column\_information  
between the time you alter the database table and try to use the  
model for something so it knows about the right schema for the table.

-Rob

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid
