Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint

4.1. Creating the Models

First, we'll run the Rails model generator to create the models used throughout this project. The Rails model generator automatically creates stub files for the models and database migrations. Then we'll edit the generated files to add our own functionality.

expenses> ruby script/generate model Project
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/project.rb
      create  test/unit/project_test.rb
      create  test/fixtures/projects.yml
      create  db/migrate
      create  db/migrate/001_create_projects.rb

expenses> ruby script/generate model Expense
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/expense.rb
      create  test/unit/expense_test.rb
      create  test/fixtures/expenses.yml
      exists  db/migrate
      create  db/migrate/002_create_expenses.rb

The generator creates the Project model in app/models/project.rb and the Expense model in app/models/expense.rb, along with unit test stubs and test fixtures. The generator also created two migrations for us: db/migrate/001_create_projects.rb and db/migrate/002_create_expenses.rb.

Now that the model generator has created these two new migrations, we need to add the column definitions that will be used by the models as attributes. For now we'll only track the name of each project. Open up db/migrate/001_create_projects.rb and edit it to look like this:

class CreateProjects < ActiveRecord::Migration
  def self.up
    create_table :projects do |t|
      t.column :name, :string
    end
  end

  def self.down
    drop_table :projects
  end
end

We only added a single line, t.column :name, :string, to the migration. This line adds the column name of type String to the database table projects. Next, define the columns for the expenses table. Same routine: open up db/migrate/002_create_expenses.rb and add the columns project_id, description and amount.

class CreateExpenses < ActiveRecord::Migration
  def self.up
    create_table :expenses do |t|
      t.column :project_id, :integer
      t.column :description, :string
      t.column :amount, :float
    end
  end

  def self.down
    drop_table :expenses
  end
end

Assuming that the database has already been created and the database connection has been configured, we can run the migrations. This will add the tables and columns defined in the two migration files to the development database configured in config/database.yml.

expenses> rake migrate

Now that the database contains the schema for the Expense Tracker we can define the relationships between the models. A Project has many Expense objects, so add the has_many() relationship to the Project model in the file app/models/project.rb.

class Project < ActiveRecord::Base
  has_many :expenses, :dependent => :delete_all
end

We added the :dependent => :delete_all option to the has_many() call because we don't want any orphaned expenses lingering around in our database without a Project. Now define the belongs_to() relationship in the Expense model. An Expense object belongs_to() a Project because the Expense contains the foreign key. Open up app/models/expense.rb.

class Expense < ActiveRecord::Base
  belongs_to :project
end

Now that the models are defined and the database is ready to go we can move on to the next step─generating and defining the controllers.