2.5. AttributesYou'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. ColumnsLet'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:
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. AccessorsYou'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. IdentifiersThe 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
Figure 2-2. The most basic Active Record mapping ties a single table to a model object
|