Putting the schema in the model files

THE SCHEMA IN THE MODEL
a small write up on ‘putting the schema in the model’

This is a write up on an issue best covered in a mailing list thread
of Januari 2006 (see the links in the text), I repost it because I
think it deserves a place on the agenda.

== Why? ==
I was switching back and forward between the model files and the
schema.rb – off course I have “active_record.schema_format = :ruby”
in my enviroment – and naturally started thinking the following:
“Why is the model specified in two separate places?”
“Shouldn’t the model files be the only place to do model stuff?”

While this question was mainly because I was fed up switching, I kind
of felt that I was at something: that we should spread stuff over more
files/locations than stricktly nessecary. Maybe it can be called
“Don’t Spread Yourself” (DSY).

== Some research ==
Quickly I asked Mr Google several questions on this topic, and he came
up with quite a few insights on the “schema in the model” utopia I was
dreaming of.
First of all I learned the historic background of ‘not having the
schema in the model’. Originally the reason for not putting the schema
in the model was because of “Don’t Repeat Yourself” (DRY); the model
had to be specified only once, in the early rails days that was in the
database itself.

Can you imagine? Directly modifying the database? Yes dear readers,
since the salvation by “migrations” we almost forgot about it, but in
the early days of rails development there where brave coders directly
modifying databases.

I’m kidding, but the point i want to make is that the arrival of
“migrations” and the “active_record.schema_format = :ruby” option
already allows us – but does not force us – to specify the database
schema in nice ruby code in stead of in the databes it self.

The fact that these new, higher levels of control are not hiding any
stuff below is what i consider one of the powers of rails:
You can use all the nice sugar that makes it a bliss to develop on:
but it is not you to use them – you’re always welcome to get your
hands dirty, digg deep, and direclty write SQL, HTML, and (recently)
JavaScript if you want/have/need to. Maybe we can call this: “Don’t
Hide Lower Levels” (DHLL).

So since migrations and the “active_record.schema_format = :ruby”
option we don’t have to specify the model in the database, but more
important: setting up and modifying the database schema can now be
database agnostic, distributable and versionable. Migrations allow us
a higer level of abstaction.

Yet we can (IMHO) still go higher on the ladder of abstraction, closer
to the mythical “Don’t Repeat Yourself” goal, and closer to the “Don’t
Spread Yourself” goal i just came up with. This because at the current
level of abstraction (using migrations) we are:

  1. repeating ourself when filling the up() and down() methods of a
    migration
  2. spreading the model over more than one location, namely: the
    model file, the migrations (write only) and the schema.rb file (read
    only)

Didn’t you at one point, when using migrations, think of a way to
automate the filling of the up() and down() methods – doesn’t filling
these methods feel like repeating yourself? Yet most likely it did not
hurt enough to actually change it, since you’re usually only writing a
little change in a migration.

== What could it look like ==
My ideas materialized when it read this thread:
http://lists.rubyonrails.org/pipermail/rails/2006-January/009640.html

On that thread Jules posts, amoung other things, a beautiful example
of what “putting the schema in a model” could look like:


class Author < ActiveRecord::Base
has_many :posts

attribute :name, :string

attribute :email, :string do |a|
a.validate_format :with => /regex/
end
end

class Post < ActiveRecord::Base
belongs_to :author # automatically adds author_id to the table

attribute :title, :string do |a|
a.validate_presence
a.validate_length :in => 3…100
end

attribute :summary, :text
attribute :content, :text
end

[from:
http://lists.rubyonrails.org/pipermail/rails/2006-January/011325.html]

Then Jon S. comes up with a list of what needs to be done to make
migrations play along schema’s in the model:
http://lists.rubyonrails.org/pipermail/rails/2006-January/011395.html

If I understand it correctly Jon suggests that the schema changes one
makes in the model file should be used to generate migrations, that
are in their turn used to (automatically or not) propagate the changes
to the database. Jon also makes (in that first and in later posts)
some more interesting notes on how this should be implemented.

Not much later the thread stops.

== Now what? ==
I totally lack the skills and experience to write a patch for this
feature, I dont even know if this is a feature that the rails
community can agree upon (when searching the web I found also quite
some opposition towards ‘putting the schema in the model’).

Usually a relatively big patch like this would ideally be implemented
as a plugin first. While I know Ruby is highly dynamic, I don’t know
if it is possible to implement such a feature as plugin.

By explaining and reposting this issue i hope that:

  1. a discussion on the validity of ‘the schema in the model’ approach
  2. some more issues regarding the implementation of this feature can
    be straightend out.

Thank you for reading,
thanks to the Rails community,
these where my .2EUR

Cies Breijs.


“Computer games don’t affect kids; I mean if Pac-Man affected us as
kids, we’d all be running around in darkened rooms, munching magic
pills and listening to repetitive electronic music.” – Kristian
Wilson (Nintendo, Inc), 1989


“Computer games don’t affect kids; I mean if Pac-Man affected us as
kids, we’d all be running around in darkened rooms, munching magic
pills and listening to repetitive electronic music.” – Kristian
Wilson (Nintendo, Inc), 1989