Object Relational Mapping (ORM) & ActiveRecord
Jumping off from SQL, databases and tables are still important towards learning about Object Relational Mapping. It also affects the outcome of ActiveRecord. More on that later.
ORMs connect objects to tables in a relational database by using Object Oriented Programming (OOP) languages like Ruby. It cuts down on repetition. The properties and relationships of the objects are stored and accessible without writing SQL statements directly, too.
OOPs can manage database data through “mapping.”
- Classes are mapped to the inside of a database’s tables
- Instances of the classes are mapped to the database’s table’s rows
Mapping Ruby Classes to Database Tables
Ruby deals with objects. Databases deal with raw data.
Ruby objects aren’t saved into a database. A Ruby’s object’s attributes are used to create new rows in the database table. Each row represents an instance of the Ruby object.
object |id | name | album |
instance 1 | 1 | first aid kit | Lion's Roar |
instance 2 | 2 | Kylie Minogue | Abbey Road Session |
Mapping classes to a table means data is stored in an organized manner.
- Create database
- Create class table; there’s a convention to pluralize the name of the class to create the name of the table.
class Song
to a database creates thesongs
table - The class’ methods are written as column names that match the
attr_accessors
of the class.
class Song
attr_accessor :name, :album, :id
def initialize(name, album, id=nil)
@id = id
@name = name
@album = album
end
...
end
Mapping stores raw data describing a given Ruby object in a table row. To reconstruct a Ruby object from the stored data, that same row in the table is selected. When querying the database, methods are coded to access those data and convert into an instance of the appropriate class (Ruby objects).
SQLite converts the database into Ruby objects which then returns an array of data for each row [id, data_name, data_value].
def self.new_from_db(row)
instance_name = self.new
instance_name.id = row[0]
instance_name.name = row[1]
instance_name.length = row[2]
instance_name # return the newly created instance
end#Database tableobj's instance name |id | data_name | data_value |
first_aid_kit | 1 | first aid kit | Lion's Roar |
kylie_minogue | 2 | Kylie Minogue | Abbey Road Session |#the array[
id: 1, name: first aid kit, album: Lion's Roar,
id: 2, name: Kylie Minogue, album: Abbey Road Session
]
That array will then be queried to be matched and those instances (as rows) can be iterated upon.
Updating records in ORM via Dynamic ORMs:
- Get/find attributes from the row in database table
- Recreate them into a Ruby object
- Make changes to that object using Ruby methods
- Then save all updated attributes back into database
The goal of dynamic ORM is to define a series of methods that can be shared by any class. So, we need to avoid explicitly referencing table and column names. To accomplish this, we use metaprogramming (a set of code that writes code for us).
Dynamic ORMs
- Create database table
- Metaprogram based on that table
- Set up database
- Build attr_accessors from column names
- Define table name
ActiveRecord
Something similar to Dynamic ORM is ActiveRecord. It maps database tables to Ruby classes as a framework. As noted by the rubyonrails guide, ActiveRecord:
- Represents models and their data
- Represents associations between those models
- Represents inheritance hierarchies through related models
- Validates models before they get persisted to the database
- Performs database operations in an object-oriented fashion
Active Record is also a Ruby gem that provides us with a library of code that give us a lot of functionality.
The pattern begins by:
- Connecting to a database
- Create a table
- Add ActiveRecord’s
Base
methods to our class by inheritanceActiveRecord::Base
class Student < ActiveRecord::Base
end
Types of base methods include
.column_names
.create
.find
.find_by
.save
attr_accessors
ActiveRecord automatically has methods that read and alters stored data from within its tables. These methods are called CRUD (Create, Read, Update, and Delete).
Create
- ActiveRecord objects can be created from a hash, a block, or have their attributes manually set. This method returns the object and saves it to the database
Read
- Accesses data
Update
- When an Active Record object is received, its attributes can be altered and save to the database
Delete
- Active Record objects can be deleted on the spot
Migration & Rake
A language called migrations manages a database. Migrations uses rake
. Rake is a tool that automates certain jobs through rake tasks
. A task is defined through the command line to execute those jobs. Rake is a part of Ruby and needs only be created in a file called Rakefile
. In this file, the task is defined:
# Task + name of task as a symbol + block that has the code to be executed
task :hello do
# the code we want to be executed by this task
end
In Terminal, when entering rake hello
the code is executed back.rake -T
when run in the terminal gives a list of available Rake tasks and its descriptions. For these tasks to work, they need descriptions.
desc 'outputs hello to the terminal'
task :hello do
puts "hello from Rake!"
end
Rake tasks can be grouped through namespace
namespace :greeting do
desc 'outputs hello to the terminal'
task :hello do
puts "hello from Rake!"
end
desc 'outputs hola to the terminal'
task :hola do
puts "hola de Rake!"
end
end
In terminal we can use either of those grouped Rake tasks by entering:
rake greeting:hello
rake greeting:hola
How Rake and Migration interact with each other is by rake db:migrate
. Database tables are created and then migrated using a rake task. When we want to load a database, we can call on rake db:migrate
.
Rake console
This starts up the Pry console for us to play with our code. rake db:migrate
would need to be run before we entering rake console in terminal.
Setting up Migration
Migration helps alter the database schema over time without having to write SQL. It keeps records of the alteration so nothing is altered completely without history. ActiveRecord can reverse the migration by rolling it back to its previous state.
The class inherits ActiveRecord’s ActiveRecord::Migration
module. This ActiveRecord::Migration
module allows the class CreateArtists to generate the artists table.
# db/migrate/01_create_artists.rb
class CreateArtists < ActiveRecord::Migration
...some code
end
- Typically the files within
db/migrate
generates the tables with its columns. The file…/01_create_artists.rb
would usually have the class set up like so:
class CreateArtists < ActiveRecord::Migration
def change
create_table :artists do |t|
t.string :name
t.string :genre
t.integer :age
t.string :hometown
end
end
end
- Each column will state the data type followed by its name as a symbol
- By default, create_table creates a primary key called id.
Running migrations
- Run
rake db:migrate
in terminal. - The table
artists
would have its own class and file calledartist.rb
that’s also called the Model whereActiveRecord::Base
will connect to theartists
database
# artist.rb
class Artist < ActiveRecord::Base
end
Using migrations to alter/update an existing table:
A few types of alteration methods:
* Add_column :table_name, :column_name, data type for the new column
* Remove_column :table_name, :column_name, data type for the new column
* change_column :table_name, :column_name, data type for the new column
A new migration file must be created to modify any existing tables then saved before running rake db:migrate
again.
# db/migrate/02_add_favorite_food_to_artists.rb
class AddFavoriteFoodToArtists < ActiveRecord::Migration
def change
add_column :artists, :favorite_food, :string
end
end
Active Record Querying Methods
Finding information and datasets using Active Record can be done from a variety of methods that’s found in the ruby guild — http://guides.rubyonrails.org/active_record_querying.html
ActiveRecord Associations
Classes can be built to associate with one another but uses a lot of code to do it. ActiveRecord associations does this job with less code.
Types of relationships between models:
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
These associations is similar to how we dealt with venn diagram in SQL. Relationship matter and helps write less code.
Final Thoughts
Active Record is a really great tool. There’s much more to it that I’m not quite sure about yet. I hope to keep up with this topic and build my skills from it.
Originally published at christineiscoding.com