I wouldn’t go for this route when trying to convince one.
IMO database migration and the ORM are different concerns and we
should actually use the single responsibility principle with regards
to them.
For example, I prefer to maintain my database migrations in a
different project using standalone-migrations:
https://github.com/thuss/standalone-migrations
There are advantages and disadvantages using this approach, but I
still think it is a better option than integrating the migrations
directly in the application.
Disadvantages:
1- rails g model user email password_hash role:references
This wouldn't be much useful if migrations are not integrated. This
could be worked around in the standalone-migrations if they included
some generators to easy migrations generation.
The generated model class itself is so short that it is pretty fast
to create it by hand. With ActiveRecord it is “class MyModel <
ActiveRecord::Base; end”. Just replace with Sequel::Model for
Sequel.
2 - application-specific classes can't be used inside migrations (is
this really a disadvantage?)
Some people like the idea of updating some data in the database
during a migration by using the ORM itself inside the migrations.
While this can be handy sometimes, it can create some issues too.
For instance, your migration is now relying on your application code
by the time you created the migration.
After a while that code may no longer exist or do a different thing,
so this is pretty dangerous.
I've already experienced some issues in open-source projects where I
couldn’t run a migration because the code inside earlier migrations
would no longer run.
The solution provided by Rails is to use "rake db:setup" for fresh
databases, but what if you need to run several migrations because
you already have a database, but the code has changed in such a way
that some of the earlier migration code won’t run anymore?
That is one of two of the strongest reason I want to keep my
migrations in a separate project. Doing that you’ll be assuring that
no application-specific domain code will be part of the migrations.
3 - You can't know what was the specific database version in use
within some commit.
Working around this limitation is pretty simple if you're using Git.
Just use your migrations project as a submodule and every time your
classes rely on a different database state, update the commit the
submodule points to.
Advantages:
I've talked already about most of them. Here are some more:
1 - You don't risk being unable to migrate or rollback your database
due to some issue in your code
I want to be sure that I'll be able to quickly run my migrations or
rollback the database even if my application won’t boot for some
reason, like a bad initializer that relies on some network
connection that is not available or anything else. I want to just
keep it simple.
2 - You can have different applications in possibly different
languages interacting with your database while having a single
separate place to store the migrations.
Back to the subject:
I've tried to convince you not to argue about defining the
properties inside the models to avoid duplication of code in
migrations because they should be really isolated from each other
Now, I'd like to share that I like the ability to quickly see what
are the column names for some domain by looking at its source-code.
Your solution provides that, but it is not the only way to achieve
this goal.
Some people might want to document such columns by using the
attr_protected and attr_accessible methods. I don’t agree that
protection against mass-assignment is a responsibility of the
models, hence I don’t agree with the default
config.active_record.whitelist_attributes = true in application.rb.
They should be handled by the controller in a MVC or Model2
architecture.
But there is a simple solution that solves this issue for me (this
example assumes Sequel, since that is my ORM of choice):
rails r "puts User.columns.join ', '"
Then it is just a matter of replacing the comment in my classes when
the table changes (I always omit ‘id’):
class User < Sequel::Model
# columns: email, password_hash, role_id
...
end
So, I'd like to ask you how do you think your proposal could help me
if I were using ActiveRecord instead of Sequel, since I’d use the
same ideas with AR as well.
Cheers,
Rodrigo.