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 rubyonrails-core@googlegroups.com.
To unsubscribe from this group, send email to 
rubyonrails-core+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en.

Reply via email to