Iterating Over an Active Record Result Set

Problem

You've used the find method of Active Record to fetch a set of objects. You want to iterate over this result set in both your controller and its associated view.

Solution

The solution uses a database of animals with names and descriptions. Create this model with:

$ ruby script/generate model Animal

and then add the following to the generated animal migration to both define the schema and add a few animals to the database:

db/migrate/001_create_animals.rb:

class CreateAnimals < ActiveRecord::Migration
 def self.up
 create_table :animals do |t|
 t.column :name, :string
 t.column :description, :text
 end
 Animal.create :name => 'Antilocapra americana',
 :description => <<-EOS
 The deer-like Pronghorn is neither antelope 
 nor goat -- it is the sole surviving member 
 of an ancient family dating back 20 million 
 years.
 EOS
 Animal.create :name => 'Striped Whipsnake',
 :description => <<-EOS
 The name "whipsnake" comes from the snake's 
 resemblance to a leather whip.
 EOS
 Animal.create :name => 'The Common Dolphin',
 :description => <<-EOS
 (Delphinis delphis) has black flippers and 
 back with yellowish flanks and a white belly.
 EOS
 end
 def self.down
 drop_table :animals
 end end

controllers/animals_controller.rb retrieves all the animal records from the database. Iterate over the result set and perform a simple shift cipher on each animal name, storing the result in an array:

class AnimalsController < ApplicationController
 def list
 @animals = Animal.find(:all, :order => "name") 
 end end

Now display the contents of both animal arrays in views/animals/list.rhtml, using two different Ruby loop constructs:

<h1>Animal List</h1>
<ul>
<% for animal in @animals %>
 <li><%= animal.name %>
 <blockquote>
 <%= animal.description %>
 </blockquote>
 </li>
<% end %>
</ul>

Discussion

In the solution, the find command returns all the animals from the database and stores them, ordered by name, in the @animals array. This array variable is preceded by an @ sign, making it an instance variable, and therefore available to the view (list.rb).

The MVC idiom is to pass variables containing data structures to views, letting the views determine how to iterate over or otherwise display the data. So in the list view, we iterate over the @animals array with a for statement, which uses the Array class's each iterator. Each iteration stores an Animal object in the animal variable. For each animal, we print its name and description.

shows the results of our iteration in the view.

Figure 3-1. Iterating over a list of animals

See Also