#------------------------------------------------------------------------------- # ACTIVE RECORD # # An object that wraps a row in a database table or view, encapsulates the # database access, and adds domain logic on that data. # # An object carries both data and behavior. Much of this data is persistent and # needs to be stored in a database. Active Record uses the most obvious # approach, putting data access logic in the domain object. This way all people # know how to read and write their data to and from the database. # # [FOWLER] pp. 160-164. #------------------------------------------------------------------------------- require 'sqlite3' DataBase = SQLite3::Database.new('students.db') class Student # Assumes that the database contains a table created the following way: # # create table students ( # id integer primary key, # name text, # gpa real # ); attr_reader :id attr_accessor :name, :gpa def initialize(name='', gpa=0) @name = name @gpa = gpa @id = -1 end def save if @id == -1 id = DataBase.get_first_value('select max(id) from students') if id @id = id + 1 else @id = 1 end end DataBase.execute('insert or replace into students values (?, ?, ?)', [@id, @name, @gpa]) end def self.create(name, gpa) student = Student.new(name, gpa) student.save student end def remove if @id != -1 DataBase.execute('delete from students where id = ?', [@id]) @id = -1 end end def self.read(id) row = DataBase.get_first_row('select * from students where id = ?', [id]) if row student = Student.new(row[1], row[2]) student.instance_variable_set(:@id, row[0]) student else nil end end def self.read_all DataBase.execute('select * from students').map do |row| student = Student.new(row[1], row[2]) student.instance_variable_set(:@id, row[0]) student end end def inspect "Student(id: #{ @id}, name: '#{ @name }', gpa: #{ @gpa })" end end #-------------------------------------------------------------------- # Typical use cases # Initialize and save students s1 = Student.new s1.name = 'John' s1.gpa = 3.5 s1.save s2 = Student.new('Mary', 2.7) s2.save # Create a student in one step s3 = Student.create('Peter', 3.1) # Update student with id = 1 s4 = Student.read(1) s4.gpa = 3.9 s4.save # Delete student with id = 2 s5 = Student.read(2) s5.remove # Retrieve all students in an array a = Student.read_all p a