

Reversible Migrations in Rails 3.1 - rohitarondekar
http://edgerails.info/articles/what-s-new-in-edge-rails/2011/05/06/reversible-migrations/index.html

======
moe
Wake me up when they finally generate those stupid migrations automatically
(see
[http://south.aeracode.org/docs/tutorial/part1.html#changing-...](http://south.aeracode.org/docs/tutorial/part1.html#changing-
the-model)).

~~~
jarin
That probably won't happen (anytime soon at least), because Rails takes the
approach of generating your model attributes based on the table fields, not
Django's (equally valid) approach of declaring the model attributes on the
model and then generating the migrations based on that.

Personally, I prefer the Rails way of doing it, since it keeps my model files
cleaner and avoids ambiguity (to me) when adding/removing/changing attributes.
Of course, there is a tradeoff in increased startup time because Rails has to
analyze your tables, but PassengerPreStart pretty much takes care of that
annoyance for me (and I use background processing that doesn't require the
Rails environment be instantiated for every job).

~~~
snprbob86
I too prefer Rail's approach. However, I disagree that Django's approach is
equally valid :-)

I've written about this before, but here's the short version:

1) The database holds the authoritative schema. You shouldn't duplicate it in
your code.

2) What if you want to do something more complicated, like split the values in
one column into two columns? You're going to need support for manual
migrations anyway.

3) Including column declarations in your model forces the database's strong
typing system onto what should be plain old Ruby/Python objects. The result is
ineffective domain objects.

~~~
awj
Just to be contrary:

> 1) The database holds the authoritative schema. You shouldn't duplicate it
> in your code.

I care about the authoritative _data model_ , which is slightly different from
the authoritative _schema_. Beyond that, I don't _edit_ the database schema.
There are many cases where I'm happier to have a complete data model in _one_
location versus (at least) two _and_ needing to mentally parse how rails
reacts to the database schema.

> 2) What if you want to do something more complicated, like split the values
> in one column into two columns? You're going to need support for manual
> migrations anyway.

In case you didn't notice, the automatic migration was happening through a
_\--auto_ command line flag. Manual migrations exist, and are the default.

> 3) Including column declarations in your model forces the database's strong
> typing system onto what should be plain old Ruby/Python objects. The result
> is ineffective domain objects.

Why should these be plain old Ruby/Python objects? ActiveRecord _already_ is a
pretty extensive DSL for relating objects to database tables. Does including
attribute descriptions _really_ make it "not a plain old Ruby object" when we
already have well developed support for field validation and relationship
declarations?

That said, I don't think the auto migrations are good idea. You're right,
_eventually_ you'll want to do a manual migration. At that point it's
_painfully_ easy to create a situation where your manual migration depends on
properties of your model that have since changed. It's a problem akin to using
your AR classes to help manipulate data in a migration. We have a point in our
migration history we simply cannot restart from because it uses a model class
that has since been removed.

~~~
snprbob86
> I care about the authoritative data model

Me too, but the truth about the world is that all inherit complexity is
accompanied by incidental complexity :-/ You've got a database, you need to
respect it's existence.

> mentally parse how rails reacts to the database schema

It's hilariously straightforward in 99% of cases:

For each column, a getter and setter are created. The getter directly calls
read_attribute and the setter calls write_attribute. Those two methods do
standard string/integer/date/etc primitive conversion. What's there to map in
your head?

> Manual migrations exist, and are the default.

Right, that's the point I'm making. They _should be the default_. I'm also
saying that I shouldn't have to write a migration AND maintain some
declarations in the python file.

> it's painfully easy to create a situation where your manual migration
> depends on properties of your model that have since changed.

Oh, I've made this mistake. Since then, I stopped referencing my models in my
migrations. I just run raw SQL (or the shorthand Ruby functions for the most
common cases). As a result, my migrations are waaaay faster (batch updates
rather loops, etc) and I've never had this problem since.

~~~
awj
FYI, you can re-declare as much of the model class as you need and simply call
reset_column_info as a class method before using it. The models at work have
some homemade serialized attributes (don't ask), and this makes it easier to
deal with that situation.

------
nwjsmith
I've been using `:Rinvert` in rails.vim to accomplish the same thing for the
last couple of months. Extremely useful.

------
jackseviltwin
I like that the author added a section on demystifying the magic involved in
how reversible migrations actually work. I like knowing how things actually
work behind the scenes. I'd like to see the Rails community put less emphasis
on the magic and more on how things work.

------
epochwolf
About time. This has bugged me for years.

