Buy this Book
Print Book $29.99 PDF $20.99 Read it Now!
Print Book £20.99
Add to UK Cart
Reprint Licensing

Ruby on Rails: Up and Running
Ruby on Rails: Up and Running

By Bruce A. Tate, Curt Hibbs
Book Price: $29.99 USD
£20.99 GBP
PDF Price: $20.99

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Zero to Sixty: Introducing Rails
Rails may just be the most important open source project to be introduced in the past 10 years. It's promoted as one of the most productive web development frameworks of all time and is based on the increasingly important Ruby programming language. What has happened so far?
  • By December 2006, you're likely to see more published books on Rails than any of Java's single flagship frameworks, including JSF, Spring, or Hibernate.
  • The Rails framework has been downloaded at least 500,000 times in only its second year, as of May 2006. These statistics compare favorably with the most popular open source frameworks in any language.
  • The Rails community mailing lists get hundreds of notes a day, compared to dozens on the most popular web development frameworks in other languages.
  • The Rails framework has caused an explosion in the use of the Ruby programming language, which has been relatively obscure until recently.
  • The Rails buzz generates increasingly hot debates on portals that focus on other programming languages. The Java community in particular has fiercely debated the Rails platform.
You don't have to go far to find great overviews of Rails. You can watch several educational videos that show Rails in action, narrated by the founder David Heinemeier Hansson. You can watch him build simple working applications, complete with a backing database and validation, in less than 10 minutes. But unlike the many quick-and-dirty environments you've seen, Rails lets you keep the quick and leave the dirty behind. It lets you build clean applications based on the model-view-controller philosophy. Rails is a special framework.
Sure, Rails has its limitations. Ruby has poor support for object-relational mapping (ORM) for legacy schemas; the Rails approach is less powerful than Java's approach, for example. Ruby does not yet have flagship integrated development environments. Every framework has limitations, and Rails is no different. But for a wide range of applications, the strengths of Rails far outpace its weaknesses.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Rails Strengths
As you go through this book, you'll learn how Rails can thrive without all of the extensive libraries required by other languages. Ruby's flexibility lets you extend your applications in ways that might have been previously unavailable to you. You'll be able to use a Rails feature called scaffolding to put database-backed user interfaces in front of your customers quickly. Then, as you improve your code, the scaffolding melts away. You'll be able to build database-backed model objects with just a couple of lines of code, and Rails will fill in the tedious details.
The most common programming problem in today's typical development project involves building a web-based user interface to manage a relational database. For that class of problems, Rails is much more productive than any other web development framework either of us has ever used. The strengths aren't limited to any single groundbreaking invention; rather, Rails is packed with features that make you more productive, with many of the following features building on one other:
Metaprogramming
Metaprogramming techniques use programs to write programs. Other frameworks use extensive code generation, which gives users a one-time productivity boost but little else, and customization scripts let the user add customization code in only a small number of carefully selected points. Metaprogramming replaces these two primitive techniques and eliminates their disadvantages. Ruby is one of the best languages for metaprogramming, and Rails uses this capability well.
Active Record
Rails introduces the Active Record framework, which saves objects to the database. Based on a design pattern cataloged by Martin Fowler, the Rails version of Active Record discovers the columns in a database schema and automatically attaches them to your domain objects using metaprogramming. This approach to wrapping database tables is simple, elegant, and powerful.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Putting Rails into Action
You could manually install all of the components for Rails, but Ruby has something called gems. The gem installer accesses a web site, Ruby Forge, and downloads an application unit, called a gem, and all its dependencies. You can install Rails through gems, requesting all dependencies, with this command:
gem install rails --include-dependencies
That's it—Rails is installed. There's one caveat: you also need to install the database support for your given database. If you've already installed MySQL, you're done. If not, go to http://rubyonrails.org for more details on Rails installation. Next, here's how to create a Rails project:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Organization
The directories created during installation provide a place for your code, scripts to help you manage and build your application, and many other goodies. Later, we'll examine the most interesting directories in greater detail. For now, let's take a quick pass through the directory tree in the project we created:
app
This application organizes your application components. It's got subdirectories that hold the view (views and helpers), controller (controllers), and the backend business logic (models).
components
This directory holds components—tiny self-contained applications that bundle model, view, and controller.
config
This directory contains the small amount of configuration code that your application will need, including your database configuration (in database.yml), your Rails environment structure (environment.rb), and routing of incoming web requests (routes.rb). You can also tailor the behavior of the three Rails environments for test, development, and deployment with files found in the environments directory.
db
Usually, your Rails application will have model objects that access relational database tables. You can manage the relational database with scripts you create and place in this directory.
doc
Ruby has a framework, called RubyDoc, that can automatically generate documentation for code you create. You can assist RubyDoc with comments in your code. This directory holds all the RubyDoc-generated Rails and application documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Web Server
Now that we've got a project, let's start a server. Type cd chapter-1 to change to your project directory. Use the script/server script to start an instance of the WEBrick server, configured for development. If you're running Windows, preface each call to a script with ruby, and you can use either forward or backward slashes. If you're using a Unix derivative, you can omit the ruby keyword:
> ruby script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2006-05-11 07:32:08] INFO  WEBrick 1.3.1
[2006-05-11 07:32:08] INFO  ruby 1.8.4 (2005-12-24) [i386-mswin32]
[2006-05-11 07:32:08] INFO  WEBrick::HTTPServer#start: pid=94884 port=3000
Notice a couple of details:
  • The server started on port 3000. You can change the port by editing the script/server script. See the sidebar "Configuring the Server" for more configuration options.
  • We started an instance of WEBrick, a pure Ruby server.
  • Ruby will also let you use a backward slash as a path delimiter on the command line, but on Unix you must use the forward slash. Some prefer the backslash because it allows you to use the tab completion feature in the MS-DOS command prompt.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating a Controller
You've seen that Rails organizes applications into pieces with a model, view, and controller. We'll start with the controller. Use the generate script (see the sidebar "script/generate") to create a controller. We'll specify the type of object to create first and then the name of the new controller. Type:
> ruby script/generate controller Greeting
      exists  app/controllers 
/
      exists  app/helpers/
      create  app/views/greeting
      exists  test/functional/
      create  app/controllers/greeting_controller.rb
      create  test/functional/greeting_controller_test.rb
      create  app/helpers/greeting_helper.rb
You might not have expected to see so much activity. Rails created your expected controller--greeting_controller.rb. But you also got a few other files as well:
application.rb
There is not yet a controller for the whole application, so Rails created this one. It will come in handy later as a place to anchor application-wide concerns, such as security.
views/greeting
Rails knows that controllers and views usually come in pairs, so it created a directory called views/greeting.
greeting_controller_test.rb
Rails also created a test for your new controller because most Rails developers build automated unit tests to make it easy to build in and maintain quality.
greeting_helper.rb
Rails helpers provide a convenient place to prevent repetition or tedious code from cluttering your views.
Ruby developers created Rails to solve their own problems before generalizing and releasing the tool to solve your problems too. You're seeing an example of excellent experience-based design. Early Rails users noticed that right after creating a controller, they usually needed additional layers of the application, and so they modified the controller generator to save themselves a few keystrokes.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Building a View
You now have a controller that renders text, but this design can take you only so far. If you want to follow Rails MVC conventions, you should render text in a separate view instead of a controller. The sloppy design is easy enough to fix. Instead of printing raw text in a controller, render it in a view. As with many web frameworks, Rails can use a template strategy for the view. For Rails, a template is simply an HTML page with Ruby code mixed in. The Ruby code executes on the server, adding dynamic content to the HTML page.
With Rails, you can generate the view and some helpers that the view will need. Type the generate command to generate a new controller, greeting, with a view, index. (You do this to tie the view and controller together.) When it asks you whether to overwrite the controller, type n for no:
    > ruby script/generate controller Greeting index
      exists  app/controllers/

      exists  app/helpers/
      exists  app/views/greeting
      exists  test/functional/
overwrite app/controllers/greeting_controller.rb? [Ynaq] n
        skip  app/controllers/greeting_controller.rb
overwrite test/functional/greeting_controller_test.rb? [Ynaq] 
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Tying the Controller to the View
In MVC, the view usually renders model data provided by the controller. Let's set an instance variable in the controller and render it in the view. First, add an instance variable called @welcome_message to the controller:
class GreetingController < ApplicationController
   def index
      @welcome_message = "Welcome to your first Rails application"
   end
end
Now, display the new message in the view by adding a Ruby expression between <%= and %> tags. Rails renders the value of the expression within these tags, just as if the value of the expression had been printed in place. Here's a view that prints your welcome message as a level one heading:
<h1><%= @welcome_message %></h1>
Reload. You'll see the same output you got in Example 1-1, though the structure of the application is different. In Example 1-1, you rendered your view within the controller. Here, you built an RHTML template. Your HTML tags provided static structure and style, and your Ruby code provided dynamic content; in this case, a variable set within the controller.
When you're embedding Ruby code, you've got two options. Scriptlets are Ruby code, placed between <% and %> tags. Scriptlets rely on side effects, or the output of the Ruby code. Expressions are Ruby expressions placed between <%= and %> tags. The expression presents the value returned by the Ruby code.
You can experiment with the interaction between the controller and view. We've changed the controller and view for greeting to show a few examples of expressions and scriptlets in action. First, we'll set a few values in the controller:
class GreetingController < ApplicationController
  def index
    @age=8
    @table={"headings" => ["addend", "addend", "sum"],
            "body"     => [[1, 1, 2], [1, 2, 3], [ 1, 3, 4]]
           }
  end
end
Next, here's the view showing expressions and scriptlets, with both interacting with values set in the controller:
<h1>Simple expression</h1>
<p>Tommy is <%= @age %> years old.</p>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Under the Hood
As shown earlier, each time you submit a URL, you're creating an HTTP request, which fires a controller action. Any MVC framework designer needs to decide between reusing the same controller for each request and creating a new controller copy per request. Rails does the latter strategy, which it calls request scope. Each HTTP request results in a new controller instance, meaning that you'll also get a new set of instance variables for each HTTP request. That's going to affect you in at least two different ways:
  • On the plus side, you don't need to worry about threading in your controllers because each request gets a private copy of the controller's instance data.
  • On the minus side, it will be harder for you to share instance data between requests. Specifically, if you set instance variables in one controller action method, don't expect to be able to use them in later HTTP requests. You'll need to share them in a session.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What's Next?
You've created a Rails project. You've created a controller and invoked it from a browser. You've also created a view and learned how views can interact with controllers and with the Ruby language. That's a good foundation, but you've seen only two pieces of the model-view-controller design pattern. In the next chapter, you'll learn how models work. We'll create a database schema and let Rails use the schema to generate our model for us. We'll then use a Rails framework to help manage relationships between the different parts of the application.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Active Record Basics
Active Record, which controls the interaction between your application and the database, is the heart of Rails. Active Record's elegant simplicity almost completely eliminates the need for configuration; in this chapter, you'll see how Active Record's conventions reduce your configuration from hundreds of lines to a handful. You'll also see how Active Record's metaprogramming dynamically adds capabilities to your classes, based on the contents and structure of the database. Finally, you'll use Active Record's elegant extensions of Ruby to quickly validate your code with less effort than ever before.
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introducing Photo Share
For the remainder of this book, we'll be working on a single application called Photo Share, a database-backed web application that allows users to share photos among acquaintances. We'll start with these simple requirements, called user stories:
  • Let a user view a set of photos on the Web so others can see them.
  • Organize photos in categories.
  • Organize and view slideshows from available photos.
Rails is a database-centric development environment, so your development will usually begin with the model. You need to determine the types of objects your application will need. A good starting point is to underline the important nouns in a list of user stories. We've used italic to signify important nouns, so we'll have Active Record classes for photos, categories, and slideshows. We'll also need slides, to keep track of the position of each photo in a slideshow.
There are several important relationships:
  • A category has many photos, and a photo can have one or more categories.
  • A category can have other categories.
  • A slideshow has many slides.
  • A slide has one photo.
A simple diagram like the one in Figure 2-1 helps to show the entities and relationships in your model. Index cards work well. For many-to-one relationships, we'll use an arrow to mean belongs to, so the arrow will point from the one to the many. Two-sided arrows are many-to-many, and a line without arrows means one-to-one. We'll represent a tree with an arrow that points back to the originating class. We'll use Active Record to define each of these entities and manage each relationship. Now, let's code them in Active Record.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Schema Migrations
Here, we'll create and configure the development database. We assume that you're working from the MySQL command prompt, but you can easily use another database and any alternative user interface that allows you to update the schema. Keep in mind that it's often useful to be able to execute scripts to create your development database and test data.
Do not configure your test database as your production or development database. All data in your test database is replaced each time you execute a new test.
You'll need an Active Record model object. Don't worry about the details yet; we'll cover them later. For now, just generate the model object by typing:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Basic Active Record Classes
Whether you use migrations or SQL scripts, you'll need to follow the naming conventions. The table name photos and the definition of the id column are both significant. (With our migration, Rails created the id column automatically.) Rails uses several naming conventions:
Class and table names
If the name of your database tables is the English plural of the name of your model class, Rails can usually infer the name of the database table from the name of the Active Record class. (Active Record will have trouble with some irregulars like sheep, but supports many popular irregulars like people.)
Identifiers
Similarly, Active Record automatically finds a column called id and uses it as a unique identifier. The id column should be an integer type, and the column should be populated by the database. In this case, we'll use an auto-increment sequence. Staying with these conventions saves you some configuration, and also makes your code much easier to understand.
Foreign keys
Foreign keys should be named <class>_id. For example, our slides table will have a foreign key named photo_id.
Capitalization
When you're defining a class, capitalize the first letter of each word and omit spaces between words (commonly called camel casing). But Rails methods, database table names, columns, attributes, and symbols use underscores to separate words. These conventions are mostly cosmetic, but Rails often uses symbols to refer to a class name, so make sure you follow these conventions. For example, to represent a class called ChunkyBacon, you'd use the symbol :chunky_bacon
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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 code—it 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.
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
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Complex Classes
For Photo Share, we've built an object model in which one table relates to one class. Sometimes, you'll want to map more sophisticated object models to a database table. The two most common scenarios for doing so are inheritance and composition. Let's look at how you'd handle each mapping with Active Record. These examples are not part of our Photo Share application, but the problems are common enough that we will show them to you here.
Active Record supports inheritance relationships using a strategy called single-table inheritance, shown in Figure 2-3. With this kind of inheritance mapping, all descendents of a common class use the same table. For example, a photographer is a person with a camera. With single-table inheritance, all columns for both Person and Photographer go into the same table. Consider this table:
CREATE TABLE people (
   id INT AUTO_INCREMENT NOT NULL,
   type VARCHAR(20),
   name VARCHAR(20),
   email VARCHAR(30),
   camera VARCHAR(20),
   PRIMARY KEY (id)
);
Figure 2-3: Rails supports single-table inheritance between an entity (Person) and subclass (Photographer)
A query against Person will return people and photographers. Active Record doesn't need to build any special support to handle a query against a superclass. Subclasses are more difficult. In order to allow a query returning only Photographers, Active Record must have some way to determine the type of an object for an individual row. Active Record uses the type field for this purpose.
Now, we need classes, which are trivial:
class Photographer < Person
end

class Person < ActiveRecord::Base
end
We declare Photographer as a subclass of Person. Active Record will manage the type attribute and everything else. You'll be able to access the camera property from Photographer. We don't need these classes for Photo Share, so we'll delete them.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Behavior
Active Record lets you manipulate and find table data directly through Active Record classes and instances. If you want to work with data from a table, use the class. If you want to work with a table row, use an instance. ActiveRecord::Base class supplies many of the methods, and missing_method provides most of the rest. You can find the documentation for the latest stable Active Record version online at the following address: http://api.rubyonrails.com.
You can use other finders as well. find_by_sql lets you type SQL directly into a finder; find_all returns all records. In addition, Active Record adds a custom finder called find_by_<column_name> to each model class for each column in that model's table.
Let's use some of the methods on Photo. We'll use a finder and the destroy method to delete an object from the database:
Photo.find_by_filename("balboa_park.jpg").destroy
The methods delete and destroy are slightly different. delete aborts on minor errors, but destroy does not abort unless there's a critical database error. You can also update objects. Let's update the Photo object for cat.jpg:
>> cat=Photo.find_by_filename "cat.jpg"
...
>> cat.filename="Cat.jpg"
...
>> cat.update
...
>> puts cat.reload.filename
Cat.jpg
...
In this case, we found the cat.jpg record. We next updated the filename attribute and called update to write the changes to the database.
So far, you've used Active Record to do database operations on an object. You can also use Active Record for simple validation. For example, you can verify that the filename property exists with one line of code. Change the Photo class in app/models/photo.rb to look like this:
class Photo < ActiveRecord::Base
  validates_presence_of :filename
end
Let's see how the validation works. Go back to the console (you'll need to restart it to reload your changes), and try to save a blank photo:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Moving Forward
In the next chapter, we'll look at managing relationships between Active Record classes. We'll see most types of Active Record relationships in action, including:
  • belongs_to
  • has_one
  • has_many
  • has_and_belongs_to_many
  • acts_as_list
  • acts_as_tree
We'll build each of these into our evolving Photo Share object model. Then, we'll take a very quick look at two other relationships: inheritance and composition. By the end of the next chapter, we'll have a fully functioning, database-backed object model.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Active Record Relationships
Dealing with relationships is one of the most important jobs of persistence frameworks. The best persistence frameworks handle relationships with excellent performance for the end user and simplicity for the developer. Active Record takes advantage of the Ruby language and naming conventions to simplify both access and configuration of related data. In this chapter, we'll focus on building relationships between tables, and reflecting those relationships in your model objects.
With validation, shown in the previous chapter, you began to see the domain-specific language built into Active Record. We'll use that language to define relationships between the objects in our database. Three components specify a relationship: the relationship itself, the association or target, and named parameters. More precisely, these are:
relationship
A method, defined through ActiveRecord::Base, which defines the behavior of the relationship.
association(s)
A symbol that specifies the target of the relationship. The symbol may be singular or plural, based on the cardinality of the target.
named parameters
Like all Ruby methods, the relationship can take an optional number of named parameters, which may also have default values.
A statement defining a relationship has the form:
    relationship :association :parameter1 => value, :parameter2 => value,...
For example, you might have:
    class Slideshow < ActiveRecord::Base
      has_many :photos :order => position
Using this small amount of language, you'll be able to define complex relationships quickly. Your relationships will also be easy to read and maintain. Let's implement the full model for Photo Share, complete with relationships.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
belongs_to
The most common database relationship is many-to-one. Figure 3-1 shows how Active Record maps the "many" side of such a relationship. In Photo Share, we want users to be able to build slideshows. A slideshow contains an ordered list of pictures. We can't simply use pictures in a slideshow because a picture has no way of keeping its position in a slideshow, so we'll introduce a Slide class. We'll then need a many-to-one relationship between slides and slideshows: a slideshow consists of many slides, but each slide (a photo combined with a position) can belong to only one slideshow. To give us the flexibility that we need (we'll also want the ability to reuse photos in different slideshows), we'll need another relationship between photos and slides, but let's leave that for later.
Figure 3-1: belongs_to :association relationship between Entity (Slide) and Association (Slideshow)
As before, let's create our database tables in a migration, so it will be easy to back out any unnecessary changes. Generate a model and migration to create a new class for Slide, and another for Slideshow:
    ruby script/generate model Slideshow
    ruby script/generate model Slide
Rails generates the models and migrations for slideshows and slides. Now, edit the new migration in db/migrate/create_slideshow.rb. As before, we'll create steps to migrate up and down. The up step will create the slides and slideshows tables, and the down step will drop them, like this:
class CreateSlideshows < ActiveRecord::Migration
  def self.up
    create_table "slideshows" do |t|
      t.column "name", :string
      t.column "created_at", :datetime
end
  end

  def self.down
    drop_table "slideshows"
  end
end
Edit the new migration in db/migrate/create_slide.rb, like this:
class CreateSlides < ActiveRecord::Migration
  def self.up
    create_table "slides" do |t|
      t.column "position", :integer
      t.column "photo_id", :integer
      t.column "slideshow_id", :integer
    end
  end

  def self.down
    drop_table "slides"
  end
end
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
has_many
We'll need to implement has_many relationships on both Photo and Slideshow. Figure 3-2 shows the mapping between Active Record objects and database tables with has_many.
Figure 3-2: The entity (slideshow) has_many associations (slides) relationship is a one-to-many relationship
has_many is the other side of a belongs_to relationship, so you don't need to modify the class or table for Slide. You can merely add the relationship has_many to slideshow.rb:
class Slideshow < ActiveRecord::Base
  has_many :slides
end
And now, photo.rb:
class Photo < ActiveRecord::Base
  has_many :slides
  validates_presence_of :filename
end
By specifying that a photo has many slides, you give users the ability to use the same photo in several different slideshows. Remember: a slide is a photo and a position in a specific slideshow. So a slide can't be reused, but a photo can.
That's all you have to do to manage the second side of the relationship. Now, you can to see all of the slides associated with a photo, and all of the slides in a slideshow. As usual, you can open the console to see the model in action:
>> slide = Slide.find 1
...
>> slideshow = slide.slideshow
...
>> slideshow.slides.each {|slide| puts slide.photo.filename}
balboa_park.jpg
camel.jpg
cat_and_candles.jpg
hut.jpg
mosaic.jpg
polar_bear.jpg
police.jpg
sleeping_dog.jpg
stairs.jpg
So you get a list of slides in the slideshow, and each has an associated photo. Active Record is now managing the has_many relationship between Slideshow and Slide. You could use photo.slides in the same way. Table 3-2 shows you the metaprogramming for has_many.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
has_one
The simplest database relationship is the one-to-one relationship. With Active Record, you can implement one-to-one relationships with either belongs_to or has_one. You decide whether to use belongs_to or has_one based on where the foreign key resides. The class associated to the table with the primary key uses belongs_to, and the other uses has_one. Figure 3-3 shows a has_one relationship.
Figure 3-3: In this one-to-one relationship, a Photo has_one File
Let's take a simple example. Hypothetically, you could have decided to implement photos and files in separate tables. If you put a foreign key called photo_id into the files table, you would have this Active Record Photo class:
class Photo < ActiveRecord::Base
  has_one :file
  ...
end
has_one is identical to belongs_to with respect to metaprogramming. For example, adding either has_one :photo or belongs_to :photo to Slide would add the photo attribute to Slide. We really have no need for adding an extra table to manage a file, so let's move on to the next relationship.
Many-to-many relationships are more complex than the three relationships shown so far, because these relationships require an additional table in the database. Rather than relying on a single foreign key column, you'll need a relationship table. Each row of a relationship table expresses a relationship with foreign keys, but has no other data. Figure 3-4 shows our relationship table.
Figure 3-4: A has_and_belongs_to_many association builds a many-to-many relationship through a join table
Photo Share requires a many-to-many relationship between Photo and Category. A category can hold many photos, and the same photo can fit into more than one category. As always, you'll start with the database. You'll need to create a table called
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What You Haven't Seen
Active Record is too big to cover in detail in such a short book, but you should know about its major capabilities. You'll find each of these capabilities in Active Record, complete with documentation:
Nested sets
Nested sets are useful for storing very large trees when you'd like to retrieve all descendents often. The nested set uses an algorithm that expresses the set as a depth-first traversal of the tree. See the Active Record documentation at http://api.rubyonrails.com for details.
Overrides
You can declare your own accessors instead of using the ones that Active Record generates. Your new ones override those provided by ActiveRecord::Base.
Versioning
Active Record uses the column lock_version, if it exists, to manage concurrency using a technique called optimistic locking. With this technique, a database engine can store multiple versions of each piece of data and maintain database integrity if many applications need the same piece of data.
Count caching
Rather than using SQL to compute the number of