Object-Relational Mapping(ORM) is a technique that allows you to query and change data in a database using an object-oriented approach. When using an ORM, your classes will be database tables and instances of those classes will exist as rows in those tables. Using an ORM allows a developer to cut down on repetitive code while also implementing conventional, organized patterns. These practices keep a code base clean and readable, which is important especially when many developers will be working on the code.
There are patterns that you will see when using an ORM that are worth taking note of. While classes are typically defined with a singular word, a class's corresponding table will be plural. If we have a
Book class, the corresponding table will be
books. Instances of the
Book class will be stored in the
books table as rows, and attributes for those instances will be stored in columns in the
Active Record is an ORM library that can be used with Ruby. Active Record comes with many built in methods that make it easier to manipulate our data. To use the Active Record gem in your code, you can simply run
gem install activerecord in your terminal, or by including it in your code's
To make use of Active Record's built-in ORM methods, we need to make our Ruby class a subclass of
class Book < ActiveRecord::Base end
Book class is able to talk to the
books table in the database. Something important to keep in mind when using Active Record is that Active Record follows convention over configuration. This means that as long as you follow the conventions adopted by Active Record, you will need to write very little to no configuration for your models. It is very important that your class names are singular and table names are plural. As long as a developer follows this rule, Active Record can save developer's a lot of time and make their code much more readable.
Making our Ruby classes subclasses of Active Record gives them access many methods. One very useful method is that
attr_accessors are usable with our code without having to explicitly write them in. I've defined some other useful methods from Active Record below, but I recommend any developer that is interested in using Active Record to read the Active Record docs to see all that it can really do.
Retrieve a list of the columns in a table:
Book.column_names #=> [:id, :name, :author, :genre]
Creates a new object for the class and saves the instance to the class's corresponding table
Book.create(name: 'The Stranger', author: 'Albert Campus', genre: 'Philosophical novel') # INSERT INTO books (name, author, genre) VALUES ('The Stranger', 'Albert Campus', 'Philosophical Novel') #=> #<Book: 0x00009f785d0832b0 id: 1, name: "The Stranger", author: "Albert Campus", genre: "Philosophical novel">
Return all the records from a table as instances of its class
Book.all # SELECT "books".* FROM "books" # => [#<Book: 0x00009f785d0832b0 id: 1, name: "The Stranger", author: "Albert Campus", genre: "Philosophical novel">]
Retrieve an object from the database by its
Book.find(1) # SELECT "books".* FROM "books" WHERE "books"."id" = 1 LIMIT 1 #=> #<Book: 0x00009f785d0832b0 id: 1, name: "The Stranger", author: "Albert Campus", genre: "Philosophical novel">
Find an object by any attribute, such as
Book.find_by(author: 'Albert Campus') # SELECT "books".* FROM "books" WHERE "books"."author" = 'Albert Campus' LIMIT 1 #=> #<Book: 0x00009f785d0832b0 id: 1, name: "The Stranger", author: "Albert Campus", genre: "Philosophical novel">
Active Record migrations are used to set up our database, and we use this format for many reasons. They provide a history of the changes made, providing version control for our database. Using Active Record migrations also allows us to forego writing SQL statements to create or change tables, as Active Record will do this for us under the hood.
To tell Active Record how we want it to connect to our database, we will use a
config/database.yml file. This file is used by convention with Active Record to provide details about how to connect with our database. For this example, we will be using SQlite, but Active Record does support other database adaptors. This is what it looks like:
development: adapter: sqlite3 database: db/development.sqlite3 test: adapter: sqlite3 database: db/test.sqlite3
Now let's set up our
environment.rb file. This file requires the gems in our Gemfile to give our program access them them.
ENV["RACK_ENV"] is our environment variable, which is set to development in this example.
RACK_ENV is a specific environment variable used by the
sinatra-activerecord gem to determine what database to connect to. Our
environment.rb file contains the following:
ENV["RACK_ENV"] ||= "development" require 'bundler/setup' Bundler.require(:default, ENV["RACK_ENV"])
To create a migration to set up our books table, we will run the following command in our terminal:
bundle exec rake db:create_migration NAME=create_books
We use bundle exec rake to access our rake file that gives us a multitude of commands that can be run in the terminal, and the above code is used to create a new migration. This command generates a new file in
20221116095220_create_books.rb. The timestamp at the beginning is crucial for Active Record as it tells your program which order to run the migrations. The following code will be in the newly created file:
class CreateBooks < ActiveRecord::Migration[6.1] def change end end
Since we are using this migration to create a new table, we will use the
create_table command to do so. When we create our table, we will provide the attribute names for the columns as well as the datatype for each of those columns. The id column is dynamically generated, so there is no need to include it here!
class CreateBooks < ActiveRecord::Migration[6.1] def change create_table :books do |t| t.string :name t.string :genre t.string :author end end end
Now that the file is set up and you've defined how you want your table to look, we must run the migration! This will create a new database file based on the contents of your migration, and it will also create a
db/schema.rb file which will give you a quick view of the set up of your database. We run our migration with the following command in the terminal:
bundle exec rake db:migrate
At this stage, our
db/schema.rb file will look like this:
ActiveRecord::Schema.define(version: 2022_11_16_095220) do create_table "books", force: :cascade do |t| t.string "name" t.string "author" t.string "genre" end end
That's it! The table now exists in the database with the columns that we have defined in our migration, as well as an id column. This is meant to serve as a brief guide to get started with Active Record migrations, but there is so much more that you can do using Active Record! Some of the most powerful use cases for Active Record involve creating associations between classes and tables. I encourage you to check out the resources below on Active Record Basics and Active Record associations to see all that Active Record can help you accomplish. Happy Coding!