ActiveRecord: Object-Relational Mapping For Rails

CS 142: Web Applications (Winter 2015)
Home Class Info Lectures Projects Staff
ActiveRecord: Object-Relational Mapping for Rails

Lecture Notes for CS 142 Winter 2015 John Ousterhout

  • Additional reading for this topic:
    • Chapters 5 and 6 of The Rails 3 Way.
    • RailsGuides: Active Record Query Interface, Active Record Associations, and Rails Database Migrations.
  • Object Relational Mapping (ORM): simplify the use of databases in applications.
    • Use objects to hold database records
      • One class for each table in the database
      • Objects of the class correspond to rows in the table
      • Attributes of an object correspond to columns from the row
    • Manage the movement of information between objects and the back-end database.
    • Manage relationships between tables (joins), turn into Ruby collections.

ActiveRecord Basics

  • Model: a Rails class corresponding to a database table
  • ActiveRecord:
    • Base class for models in Rails
    • Implements Object Relational Mapping
  • Example table: SELECT * FROM students; +----+-----------+------------+------+------+ | id | name | birth | gpa | grad | +----+-----------+------------+------+------+ | 1 | Anderson | 1987-10-22 | 3.9 | 2009 | | 2 | Jones | 1990-04-16 | 2.4 | 2012 | | 3 | Hernandez | 1989-08-12 | 3.1 | 2011 | | 4 | Chen | 1990-02-04 | 3.2 | 2011 | +----+-----------+------------+------+------+
  • Create a class for this table (app/models/student.rb): class Student < ActiveRecord::Base end
  • Or, just use the rails program: rails generate model student This also creates a migration that will create the database table (see below).
  • ActiveRecord examines the database schema for this table and uses metaprogramming to make appropriate attributes and methods available in the class automatically.

CRUD with ActiveRecord

  • Create a new record in the table: student = Student.new student.name = "Williams" student.birth = "1989-11-16" student.gpa = 2.8 student.grad = 2012 student.save()
  • Read: student = Student.find(187) student = Student.find_by(name: "Hernandez") student = Student.find_by_name("Hernandez") smarties = Student.where("gpa >= 3.0") smarties = Student.order("gpa DESC").limit(10)
    • Can also issue full SQL queries
  • Update: student = Student.find(187) student.gpa = 4.0 student.save()
  • Delete: Student.find(187).destroy()
  • Many conventions here:
    • Model class named Student
    • Class file student.rb
    • Database table named students
    • Same names for database columns and attributes of Student objects
    • Automatic pluralization and (de)capitalization: from Student class to students database table.
    • Automatic conversion between camel-case and underscores: BlogComment converts to blog_comments.

Relationships between tables

  • Many-to-one (e.g. students -> advisor):
    • Database tables: SELECT * FROM students; +----+-----------+------------+------+------+------------+ | id | name | birth | gpa | grad | advisor_id | +----+-----------+------------+------+------+------------+ | 1 | Anderson | 1987-10-22 | 3.9 | 2009 | 2 | | 2 | Jones | 1990-04-16 | 2.4 | 2012 | 1 | | 3 | Hernandez | 1989-08-12 | 3.1 | 2011 | 1 | | 4 | Chen | 1990-02-04 | 3.2 | 2011 | 1 | +----+-----------+------------+------+------+------------+ SELECT * FROM advisors; +----+----------+-----------+ | id | name | title | +----+----------+-----------+ | 1 | Fujimura | assocprof | | 2 | Bolosky | prof | +----+----------+-----------+
    • Additional declarations in the models class Student < ActiveRecord::Base belongs_to :advisor end class Advisor < ActiveRecord::Base has_many :students end
    • Can now reference the tables as if their objects are connected: advisor = Advisor.find_by_name("Fujimura") for student in advisor.students do ... end student = Student.find_by_name("Chen") student.advisor = Advisor.find_by_name("Bolosky") student.save
    • ActiveRecord automatically creates new methods in the various classes, (such as Advisor.students) which query information from the database as needed.
  • Many-to-many (e.g. students -> courses):
    • Database tables: SELECT * FROM courses; +----+--------+-----------------+-------------+ | id | number | name | quarter | +----+--------+-----------------+-------------+ | 1 | CS142 | Web stuff | Winter 2009 | | 2 | ART101 | Finger painting | Fall 2008 | | 3 | ART101 | Finger painting | Winter 2009 | | 4 | PE204 | Mud wrestling | Winter 2009 | +----+--------+-----------------+-------------+ SELECT * FROM courses_students; +-----------+------------+ | course_id | student_id | +-----------+------------+ | 1 | 1 | | 3 | 1 | | 4 | 1 | | 1 | 2 | | 2 | 2 | | 1 | 3 | | 2 | 4 | | 4 | 4 | +-----------+------------+
    • You must define the database table courses_students (names of classes in alphabetic order).
    • No need to define a CourseStudent model.
    • Additional declarations in the Student and Course models: class Student < ActiveRecord::Base has_and_belongs_to_many :courses ... end class Course < ActiveRecord::Base has_and_belongs_to_many :students ... end
    • Again, ActiveRecord creates additional methods in the two classes so you can reference back and forth between Student and Course instances: student = Student.find_by_name("Anderson") courses = student.courses() cs142 = Course.find_by_number("CS142") courses << cs142

Migrations

  • Managing database schemas is complex and error-prone
  • Migrations in Rails provide a framework that makes schema evolution much easier to manage:
    • Assume from the start that the schema will go through a series of versions.
    • A migration provides code that will update the database schema from one version to the next, and back again.
    • Rails keeps track of the database's current version and will apply appropriate migrations to switch it to any other version.
  • Don't create database schemas with SQL: use migrations
  • Migration to create a new table: class CreateStudents < ActiveRecord::Migration def change create_table :students do |t| t.string :name t.date :birth t.float :gpa t.integer :grad end end end
    • Primary key id created by default.
  • Migration to add a new column to the table: class AddAdvisor < ActiveRecord::Migration def change add_column :students, :advisor_id, :integer end end
  • Command to generate a new migration: rails generate migration create_advisors
  • Or, create model and initial migration together: rails generate model advisors
  • Command to run migrations (migrate to most recent version): rake db:migrate
  • Command to run migrations (migrate to specific version): rake db:migrate VERSION=20090130180755
  • Back out all migrations: rake db:migrate VERSION=0
  • Destroy the database, create a new database, and run all migrations to bring the new database back up to date rake db:migrate:reset
CS 142: Web Applications (Winter 2015) Stanford University

Tag » What Is Activerecord In Rails