Most Rails users are familiar with ActiveRecord. But what does that mean? What is ActiveRecord's approach to object relational mapping? And what are the alternatives?
16. An object that wraps a row in a database table or view,
encapsulates the database access, and adds domain logic on
that data.
Martin Fowler, PoEAA, 160.
20. 1. Too much magic.
http://cgi.ebay.com/MEDIEVAL-MAGE-KING-BLACK-TUNIC-COSTUME-SCA-LARP-_W0QQitemZ250373576829QQcmdZViewItemQQimsxZ20090215?IMSfp=TL090215143008r8810#ebayphotohosting
40. An object that wraps a row in a database table or view,
encapsulates the database access, and adds domain logic on
that data.
Martin Fowler, PoEAA, 160.
48. A layer of Mappers (473) that moves data between objects and
a database while keeping them independent of each other and
the mapper itself.
Martin Fowler, PoEAA, 165.
50. Explicit property mapping
class Message
include DataMapper::Resource
property :name, String
property :body, Text
property :created_at, DateTime
validates_presence_of :name
end
56. Chainable finders
class Zoo
def self.open
all(:open => true)
end
def self.big
all(:animal_count.gte => 1000)
end
end
big_open_zoos = Zoo.big.open
57. Associations
class Article
include DataMapper::Resource
property :id, Serial
property :title, String
property :content, Text
belongs_to :author
end
class Author
include DataMapper::Resource
property :id, Serial
property :name, String
has n, :articles
end
Article.all('author.name' => 'Michael')
Because your database and your OO code are unlike things. Different paradigms.
So in a sense, any time you use a relational DB + OO, you’re going to do some sort of object relational mapping.
May be formal or informal.
So data types are not identical
Your DB has a formal definition independent of the use of the data.
This is a big one.
In OO, you follow references - an object can “point” to another object, and so on.
In SQL, you logically join sets of data together.
Any bit of data can be joined to any other bit.
In OO, ideal is to hide as much as you can and only expose a public interface.
declarative vs. active - declare that certain kinds of data are acceptable, vs. actively checking at certain points in time.
SQL doesn’t directly have a concept of inheritance. Fundamental to OO.
Finally, different purposes.
Define structure for data (and hold that data)
vs.
Doing something
So basically, ORM are translators between unlike things. Like any translation,
this isn’t going to be perfectly smooth, and there will always be tradeoffs.
In this talk, Dan and I are going to talk about these tradeoffs by looking at three approaches to ORM with Ruby.
You’re probably familiar with this already, so I won’t show much code here or talk about how to use AR. Instead, let’s talk for a few minutes at a more theoretical level.
In this pattern, an object wraps each DB row. This single object handles both domain logic and database access. What's unique about this?
Other approaches might not treat each row as an object, or might combine multiple rows into a single object.
Others might separate these, filtering the data through a logic layer, instead of exposing both side-by-side.
class User < ActiveRecord::Base
end
That does a _lot_. And from looking at this, you have no idea exactly what it did. You have to check the db schema in order to figure that out.
The good news is that convention dominates. Once you know the conventions, you generally aren't surprised.
This is true, by default. N+1, loads all columns, etc.
It would be really nice if it could do these things.
But at the same time, it provides facilities for these sorts of optimizations.
This is part of the reason that alternative ORMs got started.
The thing is, it isn't true any more. At least not entirely.
This guy, Josh Peek, made Rails 2.2 thread safe.
And this guy, who you may recognize, added the current connection pooling.
The fact is, as a AR developer, you can pretty much forget how to write a join.
This isn't really a limitation of AR - some could say that it’s a feature. But at the same time, you really do need to know SQL if you’re going to use a relational database.
That said, my SQL skills have atrophied as a Rails developer. On our newest project, Luke and I have had to do quite a bit of custom SQL, and we've tried to make our DB layer a bit smarter and more robust. Which leads to the next criticism...
Rails makes polymorphic associations easy and multi-table inheritance hard.
But polymorphic associations: bad idea. Cuts out a join table, but hurts referential integrity. But because it’s easy, you see a lot of it.
Is this a valid criticism? It usually isn’t that hard to fight against AR’s conventions, and most of the time, you don’t want to.
This is bad. Basically, foreign keys require a plugin. Redhill. This plugin works, but isn't all that actively maintained, and some things (constraints) aren't even supported by that.
You can always run a bare connection.execute() statement, but this won't get dumped into your schema.rb file, which is bad.
According to DHH et al, you don't need DB constraints, and you want a dumb DB.
4. Access your database directly.
Company 1 may not exist.
Or
I.e. you make a mistake
I.e. you make a mistake.
This probably isn’t a problem for you, but it might be for some of the other people you work with.
Sequel is a thread-safe DB library with a lightweight ORM
Follows the ActiveRecord pattern
So you don’t have to write much real SQL
So you don’t have to write much real SQL
The Sequel ORM is very similar to AR, at least on the surface.
Does many of the things that Rails does, at least the basics.