Object Relational Mapping(ORM) — RUBY

David Medina
3 min readMay 9, 2021

--

What is Object Relational Mapping(ORM)?

A technique of accessing a relational database using an object-oriented programming language. Object Relational Mapping is a way for programs to manage database data by “mapping” database tables to classes and instances of classes to rows in those tables. ORM is a conventional way to organize programs when we want those programs to connect to a database.

Why use ORM?

Two good reasons are:

  • Cutting down on repetitive code.
  • Implementing conventional patterns that are organized and sensical.

Cutting Down on Repetition

Let’s use the example that we have a program that helps a veterinary office keep track of the pets it treats and those pets’ owners. Such a program would have a Owner class and a Cat class. The program needs to connect to a database so that the veterinary office can persist information about its pets and owners.

The program would create a connection to the database:

database_connection = SQLite3::Database.new('db/pets.db')

Create an owners table and a cats table:

database_connection.execute("CREATE TABLE IF NOT EXISTS cats(id INTEGER PRIMARY KEY, name TEXT, breed TEXT, age INTEGER)")database_connection.execute("CREATE TABLE IF NOT EXISTS owners(id INTEGER PRIMARY KEY, name TEXT)")

Regularly insert new cats and owners into these tables:

database_connection.execute("INSERT INTO cats (name, breed, age) VALUES ('Maru', 'scottish fold', 3)")database_connection.execute("INSERT INTO cats (name, breed, age) VALUES ('Hana', 'tortoiseshell', 1)")

There is a lot of repetition in the lines above. In fact, the only difference between the two lines is the actual values. Instead of repeating the same, or similar, code any time we want to perform common actions against our database, we can write a series of methods to abstract that behavior.

We can write a .save method on our Cat class that handles the common action of INSERTing data into the database.

class Cat  @@all = []  def initialize(name, breed, age)
@name = name
@breed = breed
@age = age
@@all << self
end
def self.all
@@all
end
def self.save(name, breed, age, database_connection)
database_connection.execute("INSERT INTO cats (name, breed, age) VALUES (?, ?, ?)",name, breed, age)
end
end

Now let’s create some new cats and save them to the database:

database_connection = SQLite3::Database.new('db/pets.db')Cat.new("Maru", "scottish fold", 3)
Cat.new("Hana", "tortoiseshell", 1)
Cat.all.each do |cat|
Cat.save(cat.name, cat.breed, cat.age, database_connection)
end

The connection to the database is established. Two new cats are created and then iterate over our collection of cat instances stored in the Cat.all method. Inside this iteration, we used the Cat.save method, giving it arguments of the data specific to each cat to INSERTthose cat records into the cat's table. We now have some re-usable code––code that we can easily use again and again to "save" or INSERT, cat records into the database.

Design

Follow the convention: classes are mapped to or equated with tables and instances of a class are equated to table rows.

If we have a Cat class, we have a cat's table. Cat instances get stored as rows in the cat's table.

Further, we don’t have to make our own potentially confusing or non-sensical decisions about what kinds of methods we will build to help our classes communicate with our database.

--

--

No responses yet