I'm one of the maintainers of the hobofields gem Andrew Mutz mentioned earlier,
so I figured I'd toss my observations in.
To me, an in-model DSL provides two major benefits:
- enhanced readability of the class, both for the developer and for other code.
For instance, compare these two models (loosely extracted from an old Rails 2.3
app of mine):
class CertificationPayment < ActiveRecord::Base
validates_numericality_of :year, :only_integer => true, :greater_than => 2000
belongs_to :detail, :class_name => 'CertificationDetail'
end
VS
class CertificationPayment < ActiveRecord::Base
fields do
year :integer
contact_number :phone_number
payment_method :payment_method
check_number :string
amount :decimal, :scale => 2, :precision => 10
timestamps
end
validates_numericality_of :year, :only_integer => true, :greater_than => 2000
belongs_to :detail, :class_name => 'CertificationDetail'
end
I believe most developers would regard the second form as more understandable,
especially if they were new to the codebase.
In the case of hobofields, there was the additional need to have more-specific
type information for use by code that essentially generates forms on-the-fly at
application load time. This arguably makes it *more* database-agnostic, since
code that reflects on field types isn't tied to ActiveRecord::Base.columns.
- The second motivation was to provide a richer type system for fields than
would otherwise be available. For instance, two of the fields in the example
above use application-defined types (:phone_number and :payment_method).
Underneath the hood, both fields eventually wind up as plain :string columns in
the DB, but this interface allows the developer to be more specific in the
description.
In addition, the rich types can provide additional validation, normalization,
and formatting capability - :phone_number, for instance, normalizes whatever
the field is set to to remove punctuation, validates that the resulting string
is the correct number of digits, and formats the data back into US format for
display. None of this is particularly amazing - but the truly handy thing with
rich types is that it is modular - changing an application to store / format
non-US phone numbers with this method would be a matter of redefining the type,
not rewriting validations in many places. Validation objects can certainly
streamline this in plain AR, but you still need to remember to use them every
time you have a model that uses that type.
----
Regarding migration generation, the hobofields gem takes a somewhat deeper
approach. Our migration generator does the following:
- ignores models without a 'fields' block. This avoids the "gotta use it
everywhere" problem.
- interactively prompts the user to decide between removing things vs. renaming
things, since it's not possible to determine which action is correct in most
cases.
- has the option to either generate the migration and run it, or just generate
it. This allows for the addition of data conversion code, DB-specific setup (FK
constraints, etc) and full user control over the migrations if desired.
----
Regarding the "developer beholden to an ivory tower of DBAs" issue, I'd say
this sort of thing is *still* useful, even if it isn't generating the
migrations. It provides an executable contract asserting what the code is
expecting from the DB; anybody who's ever pulled down a branch only to discover
that their development DB is out-of-sync with the code would likely appreciate
that.
----
Short story shorter (too late) - I'm not sure this is something that's yet
ready to be baked into Rails; hobofields in particular could use a good spring
cleaning and refactoring, now that it's been in production use for a couple
years. Anybody who's interested in discussing *that* further is welcome to join
us over in the hobo-dev Google Group.
Thanks,
--Matt Jones
--
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Core" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/rubyonrails-core?hl=en.