2.1. Active Record
Basics
Martin Fowler cataloged the Active Record design
pattern in a book called Patterns of
Enterprise Architecture. The Rails
framework is an implementation of that idea. With any Active Record
implementation, users manipulate database tables through record
objects. Each record represents a row in a database table, and each
Active Record object has CRUD (Create, Read, Update, and Delete)
methods for database access. This strategy allows simple designs
and straightforward mappings between database tables and
application objects.
The Rails persistence framework is like Martin
Fowler's Active Record on steroids. The Rails version adds some
capabilities that extend Active Record. Table 2-1 shows a list of critical
differences, followed by the benefit to the developer.
Table 2-1. Rails versus Active
Record
|
Difference
|
Benefit
|
|
Rails adds attributes automatically, based on
the columns in the database.
|
Rails developers do not have to specify
attributes in more than one place.
|
|
Rails adds relationship management and
validation through a custom internal language.
|
Rails developers can declare relationships and
model-based validation to be managed by the framework without
relying on code generation.
|
|
Rails naming conventions let the database
discover specific fields.
|
Rails developers do not need to configure
primary and foreign keys because Active Record discovers them
automatically.
|
Each Rails enhancement improves readability and
reduces the amount of code that you have to write and maintain.
You'll find Active Record to be all at once elegant, powerful, and
pragmatic.
2.1.1. Wrapping,
Not Mapping
With most Java-based persistence frameworks, you
independently build a database table and an object. You then build
a map between the two with code or XML configuration. We call this
strategy object relational
mapping (ORM). Java developers
usually favor mapping because it can support many different kinds
of database schemas. The drawback of ORM is that your code has more
repetition because you need to specify each column in the database,
in your object model, and often in configuration files, too.
But Active Record uses a wrapping strategy, not a mapping strategy. A Rails
developer starts by building a relational database and wraps each
table with an Active Record class. Each instance of the class
represents a row of the database. The framework then automatically
discovers columns from the database table, and dynamically adds
them to the Active Record class. Using Active Record, you can build
a simple mapping to a typical table in two lines of code.
2.1.2. A Brief
Example
Let's look at a brief Active Record example and
walk through the highlights. Then, we'll implement a working Active
Record model, and walk through the finer points in more detail.
Consider the following Active Record class, which associates many
photos to a category:
class Photo < ActiveRecord::Base
belongs_to :category
end
This Active Record class is surprisingly
complete. There are only a few lines of configuration (versus
dozens in a typical Java framework), and no duplication between the
model and the schema. Let's break it down:
class Photo < ActiveRecord::Base
We define a class called Photo that's a
subclass of the Base class in the ActiveRecord
module. From naming conventions and the name Photo, Active
Record knows that this class wraps a database table called
photos. That information is enough to let Base
query the database system tables for all the columns of
photos. Base adds metadata from each column, such
as column names, types, and lengths, to Photo. It then
adds an attribute to Photo for each column in the
database:
belongs_to :category
Here, you see an example of a domain-specific language (DSL). A DSL is
created especially to handle a certain domain. This language
supports object relational mapping. belongs_to is actually
a method of Base, and :category is a Ruby symbol.
We use this method to tell Active Record about a many-to-one
relationship between Photo (which wraps the table
photos) and Category (which wraps the table
categories). THRough naming conventions, Base
discovers the column responsible for managing the relationship.
belongs_to then adds the methods and attributes to
Photo that users of Book will need to manage the
many-to-one relationship. For example, you'll learn later that each
Photo object has an attribute called category. So
this relationship is nearly trivial to implement, but it adds great
power to Rails.
2.1.3. The Secret
Sauce
Each great framework has one or more features
that set it apart from the rest. The Rails implementation of Active
Record uses a secret sauce composed of
three revolutionary ideas:
Convention over
configuration
-
Using Active Record, you'll adhere to a couple
of conventions that we'll discuss through the course of the
chapter. If you follow the conventions, Active Record can discover
most of what it needs to know about the database schema, keeping
your code simple and elegant.
Metaprogramming
-
Active Record discovers features of your
database schema and automatically adds them to your object model.
For example, Active Record automatically adds to your objects an
attribute for every column in your database.
A language for
mapping
-
Active Record uses Ruby to build a language in a
language. You'll use a mapping language to specify relationships
between your tables.
Each of these ideas is a dramatic departure from
what you'd normally see with mapping frameworks. The results, too,
are dramatic. You'll find yourself creating more powerful
persistent models with less effort than ever before. Let's get to
work and see how Active Record works.
 |