Section 2.5. Attributes


2.5. Attributes

You've now seen metaprogramming in action through the console. Your applications will use your model objects in the same way. One of the drawbacks of Active Record is the terseness of the source codeit won't tell you much. If you know what's going on under the covers, though, you can easily understand what attributes and methods your class supports.

2.5.1. Columns

Let's review what happens when Ruby loads the Photo class. From the class name Photo , Active Record infers that the database table name is photos . It then queries the database system tables, which have detailed information about the tables in the database, to get the photos table definition. Next, it places information about the definition of each column into the @@columns class variable. @@columns is an array of Column objects; each column has these attributes:



name

The name of the database column.



type

The Ruby type of the attribute this column will generate.



number

A Boolean value that's TRue if the column's data is numeric. You'll access it through the accessor method number? .



limit

The maximum size of the data element. For example, for a database column of type varchar(45) , the limit would be 45.



null

A Boolean value that's true only if the column can be set to null . You'll access it through the accessor method null? .



text

A Boolean value that's true only if the column can be interpreted as text. You'll access it through the accessor text? .



default

The default value you specified in the table definition.



primary

A Boolean value that's true if the column is the Rails unique identifier. You'll access it through the accessor method primary? .

Your applications can use this column metadata to build dynamic user interfaces. Scaffolding, discussed in Chapter 4, uses this technique. Normally, you want to get the data only for a column, so you'll use an attribute's accessors.

2.5.2. Accessors

You've seen that you can access the database columns of a photo by simply calling an accessor like photo.filename . The Rails implementation isn't necessarily what you'd expect. You might expect to see the accessor for filename as a method on photo . Strangely, if you type:

 photo.methods.include? 'filename' 

in the console, you get false , which means that there's no explicit filename accessor for photo . Active Record uses a Ruby metaprogramming trick to attach attributes. It overrides the method_missing method, which gets invoked if you call a nonexistent method of some object. Consider this program:

 class Talker   def method_missing(method)     if method.to_s =~ /say_/      puts $'     end   end end 

This Talker class responds to any message beginning with say_ , even though no method beginning with say_ exists. For example, Talker.new.say_hello prints hello . Active Record uses this trick to implement accessors. As a consequence, include? returns false for accessors because the class doesn't include an explicit accessor method. You'll see later that Active Record also generates custom finders , like find_by_filename , for each class.

2.5.3. Identifiers

The id attribute is special to Active Record because that column serves as the primary key for the database table. Our migration created the id column, and a primary key based on the id , automatically. The underlying table definition, shown in Figure 2-2, identifies the primary key with the primary key(id) statement. You might expect Active Record to recognize the unique identifier by seeing which columns are included in a table's primary key, but this strategy is not always possible. Some database managers don't have simple APIs to discover primary or foreign keys, so Active Record uses the id naming convention instead (see Table 2-2).

Table 2-2. Active Record adds these methods and attributes to model objects at runtime

Features

Purpose

Methods

find_by_<column_name>

Active Record adds a class method to the class for each column in the database, including id . For example, Active Record adds find_by_id , find_by_name and find_by_email to a class wrapping a table having id , name , and email columns.

find_by_<column_name>_and_<column_name>

Active Record also adds finders that combine groups of attributes. For example, a Person class wrapping a table with name and email columns would support Person.find_by_name_and_email(name, email) .

Attributes

<column_name>

Active Record creates an attribute with getters and setters for each property in the database. For example, photo.filename = "dog.jpg" would be legal for a photo instance of a class wrapping a table with a filename column.


Figure 2-2. The most basic Active Record mapping ties a single table to a model object

Identifiers and Legacy Schemas

In a typical Rails migration script, you will not see the id column. Rails manages the id field for you by default. In the typical case, Active Record maps the id onto a database sequence, so the database creates the initial value of id . You don't have to let Active Record manage your identifiers. For example, you could have a Photo class with a timestamp attribute called created_at :

 class Photo < ActiveRecord::Base   set_primary_key "created_at" end 

There are some restrictions, though. The most prominent restriction (as of Rails 1.1) is that you can't use composite keys, or primary keys using more than one database column. If you need to use composite keys, one way to solve the problem is to introduce a new column to serve as your identifier. It need not be the primary key.

Alternatively, you could create a database view. A view is a logical view of database data. You can access the results of any query as a view. You could use a view to introduce a new column or to combine several existing columns into one. Active Record could then use the view instead of the table.

Rules for updating views vary across database managers, so depending on your database manager, you'd either have to customize Active Record or use views only for read-only tables. Both approaches have been successfully used in production applications.




Ruby on Rails[c] Up and Running
Ruby on Rails[c] Up and Running
ISBN: B003D3OGCY
EAN: N/A
Year: 2006
Pages: 94

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net