Steve wrote:
From my perspective, writing DDL is the most certain way to get what
you want. But it's a mental context switch that not everyone wants to
make regularly.
I have never had a problem getting AR migrations to produce the DDL I
need. For database specific options you can define the
ptions
parameter to pass into the relevant migration method (e.g. create_table,
etc.). Also standard parameters like :limit, :null,
rimary, etc. are
available and aren't used enough in my experience by Rails developers.
In addition to this I have internally developed AR migration extensions
where I can simplify things in a more convenient way just by extending
the relevant AR adapters and in the process reduce human error
considerably and thus produce a more consistent DB schema:
---
# pastie:
http://pastie.caboo.se/private/2jrjnodsjsxxgi4stbjmg
class << self # yes I use this Ruby idiom, perhaps a bit too much
up
create_lookup_table :countries
# OR
add_foreign_key :users, :country_id #, :table =>
:not_obvious_table_name
# OR
end
down
drop_lookup_table :countries
# OR
remove_foreign_key :users, :country_id #, :table =>
:not_obvious_table_name
end
end
---
In the above example "create_lookup_table" creates a specific type of
table that usually has an :id, :code (which is unique), :name, where
:code has a unique index declared on it. This is just a small sample of
extensions I have internally developed for specific needs, but the point
is that customization of AR migrations is fairly painless for a Ruby
developer, which yields a much lower incidence of human error and schema
inconsistencies than directly writing DDL and streamlines the process of
creating consistent schemas with little mindset switching.
Steve also wrote:
But it turns out there are some migrations that can't really be
reversed, such as removing columns. You can add the columns back
in but the data can't easily be reconstructed.
Yes, but this is why AR migrations allow you to declare in the down
migration that it is an irreversible migration by raising an
IrreversibleMigration exception, if you feel that is necessary for
project sanity.
Now on the general topic of DataMapper vs. ActiveRecord. First let us
consider the original idea behind both. Both of these Ruby libraries
are based on Fowler's enterprise architecture patterns of the same name.
However, the Ruby library DataMapper doesn't appear to be written in
exactly the same vain as Fowler's pattern. The Ruby DataMapper library
promotes the use of the DataMapped objects *as* Domain Objects, which is
different to Fowler's pattern recommendation that is to use a Data
Mapper to separate the in-memory domain object from it's database
representation. ActiveRecord (the Ruby library) is consistent with
Fowler's definition of Active Record (the PofEA), except that Ruby
metaprogramming is able to hide so much of the database lookup code that
the design pattern's documented disadvantage (of not being useful for
complex domain object logic) doesn't apply as much. I feel this
difference is much overlooked and needs stating.
I have only used AR (Ruby) on production projects and only played with
DM (Ruby) on personal projects, so I am not able to give an in-depth
comparison of real world usage or performance. However, in theory a
library that follows Active Record pattern principles would be more
beneficial to use when tables more directly correlate to objects (i.e.
an isomorphic schema). When mapping table attributes into many object
instances you may find libraries using a Data Mapper pattern less
complex and more expressive. However, the primary advantage of Fowler's
Data Mapper pattern requires that you separate the Data Mapper class
from the Domain Object class. Of course this is complicated by the fact
that in Ruby orthogonal features can be added using metaprogramming,
which wasn't considered when Fowler wrote the PoEA book as he was was
heavily into non-metaprogramming-capable static languages at the time.
It appears that if DataMapper (the Ruby library) is able to sufficiently
hide enough database logic in more complex business logic scenarios,
then the DM library might be more beneficial to use when using a legacy
database schema where you are not able to create primarily isomorphic
relationships between class attributes and table columns, whereas AR
would be a slam dunk and simpler to use in isomorphic schema scenarios.
HTH,
Susan