Schemas and Migrations

Hello-

I’m new to the ruby-based schemas and migrations. As I’m looking over
examples and such online, I see that many of them don’t make use of
schema-enforced attributes. For example, instead of:

t.column “post_id”, :integer, :default => 0, :null => false

They do:

t.column “post_id”, :integer

So I’m wondering – is this just due to the simplicity of the examples
that don’t get hung up in details? Or, is this the general philosophy
to follow – let the model set the constraints and leave the schema to
be very simple.

I also notice that strings are not setup with :limit => xxx. Is there
any advantage to putting a limit on strings in the schema? It seems
that with MySQL, a VARCHAR(255) is just as efficient as a VARCHAR(10).
True?

Jake

Hey Jake !

I think the examples are just for brevities sake.
I use :limit’s and :default’s all over my migrations.
Setting varchar(255) vs varchar(10) does make a difference… but it
obviously depends on the size of your table, how much it’s getting
accessed… etc.

ps… Migrations r0ck !
:slight_smile:

Dylan

So I’m wondering – is this just due to the simplicity of the examples
that don’t get hung up in details? Or, is this the general philosophy
to follow – let the model set the constraints and leave the schema to
be very simple.

That’s the general philosophy that I advocate and follow in all
37signals applications. varchar(255) or varchar(50) has no barring on
the space utilized by the database. A varchar is already a “character
of variable length”, so the only difference between the two is that
varchar(50) is dictating a constraint in the database that I’d much
rather have as a validates_length_of.

So if you see any examples from my hand using the least amount of
specification possible, they’re most likely real. See
http://www.loudthinking.com/arc/000516.html for more arguments along
the same lines.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework

When I was working at Bravenet, we had a consulting contract with MySQL.
One
of the first changes Monty had us make was to set defaults and not nulls
throughout our entire schema. That was back in the 3.x days though,
things
could have changed since then, but I doubt it. Obviously this is for the
MySQL’ers out there, although I wouldn’t be surprised if other databases
had
similar properties. Only the database designer would be able to answer
that
question.

Bob S.

David Heinemeier H. wrote:

That’s the general philosophy that I advocate and follow in all
37signals applications. varchar(255) or varchar(50) has no barring on
the space utilized by the database. A varchar is already a “character
of variable length”, so the only difference between the two is that
varchar(50) is dictating a constraint in the database that I’d much
rather have as a validates_length_of.

I agree with this one. What about NOT NULL ? That’s somewhat of a
convenience for displaying information in a view. That is, if I have a
contact with phone1, phone2, it would be nice to have phone2 NOT NULL
with a blank default. That way, in my view, I can just do:

<%= c.phone1 %>

Rather than

<%= c.phone1 or ‘’ %>

Is there a way to do a validates_presence_of with defaults?

Jake

OK, Bob, you made all those changes, but did they have any
effect? I’ve seen plenty of non-productive wheel-spinning on various
projects at various companies and unless there was a reason for the
inclusion of the default and non-null constraints, this smells like
more of the same.

-Rob

That’s the general philosophy that I advocate and follow in all
37signals applications. varchar(255) or varchar(50) has no barring on
the space utilized by the database. A varchar is already a “character
of variable length”, so the only difference between the two is that
varchar(50) is dictating a constraint in the database that I’d much
rather have as a validates_length_of.

Correct me if I am wrong, but another advantage to this approach comes
in
the saving of the data. If you set the length of a field to 50 and save
100
characters, it will chomp off the data without telling the user
anything.
When the model validates_length_of, it will kick a validation error so
that
data will not be lost and the user is informed of the limitation.

~ Ben

Ben R. wrote:

Correct me if I am wrong, but another advantage to this approach comes
in
the saving of the data. If you set the length of a field to 50 and save
100
characters, it will chomp off the data without telling the user
anything.
When the model validates_length_of, it will kick a validation error so
that
data will not be lost and the user is informed of the limitation.

~ Ben

There’s been a lot of debate over this issue in the thread David posted
on his blog. I think it boils down to – how much of the model do you
put in the database. You could have -both- the model and the database
restrict the length to 50.

The advantage is that some other app (not rails) using the database gets
the same constraint so some other app can’t enter a field of length 75.
The disadvantage is repeating yourself. Since the database can really
only handle a subset of the constraints provided for by the application,
it makes more sense to me to put it in the app and repeat as necessary
(in other apps, for example).

Since I know that my database will only be used by my web app, I’m
perfectly content leaving all the constraints to rails.

Jake

<%= c.phone1 %>

Rather than

<%= c.phone1 or ‘’ %>

nil is automatically converted to “” on output:

irb(main):001:0> nil.to_s
=> “”

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework

Hi Rob,

Excellent question, the only answer I can give is that if you can’t
trust
the person who wrote the database and what he defines as a performance
enhancement or impact, who can you trust? At the query rate we were at,
every little tweak made a difference. With today’s hardware and the
further
development of MySQL, it’s probably less of an impact, but 6 years ago,
running on a P3 300 with 3 million rows was really reaching capacity,
and
that’s why we paid MySQL to analyze our stuff and recommend
enhancements.

Bob

Excellent question, the only answer I can give is that if you can’t trust
the person who wrote the database and what he defines as a performance
enhancement or impact, who can you trust? At the query rate we were at,
every little tweak made a difference. With today’s hardware and the further
development of MySQL, it’s probably less of an impact, but 6 years ago,
running on a P3 300 with 3 million rows was really reaching capacity, and
that’s why we paid MySQL to analyze our stuff and recommend enhancements.

Stale information about performance is the #1 reason make bad
decisions about premature optimization. The more low-level you’ve been
as a programmer, the higher the probability that you’ll worry about
performance before you know whether its worth worrying about.

In performance work there’s one cardinal rule: Measure! Nothing else
will sustainably give you the information necessary to make sure
you’re not wasting your time.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework

Jake J. wrote:

Is there a way to do a validates_presence_of with defaults?

Jake

Alternatively, would it be better to do this on the way out of the
database? That is:

def phone1
self.attributes[‘phone1’] || ‘’
end

Something like that? What’s the “correct” way to set this up?

Jake