A Beginner's Guide to Active Record
Tags: tutorial, programming, database
Published: 2023-06-07 20:03:03

## Contents

- [Introduction](#introduction)
- [Basics](#basics)
- [Getting started with Active Record](#getting_started_with_active_record)
  - [Set up Gemfile](#set-up-gemfile)
  - [Create models and associations](#create-models-and-associations)
  - [Create new migrations](#create-new-migrations)
  - [Migrate changes and check status](#migrate-changes-and-check-status)
- [Next steps](#next-steps)
- [Conclusion](#conclusion)
- [Resources](#resources)

## Introduction

Active Record is an essential component of web development that simplifies the interaction between a Ruby application and a relational database. It is an Object-Relational Mapping framework that provides mapping database tables to Ruby classes and enables developers to perform common database operations using familiar object-oriented syntax. With Active Record, we can easily create, retrieve, update, and delete records in the database without having to write raw SQL queries. This guide will walk you through the basics of Active Record, including setting up the necessary gems, defining models and associations, creating database migrations, and performing database operations.

## Basics

A web application can typically be broken down into three parts: the model, the view, the controller. This is known as the **Model View Controller** architecture.

> Model View Controller (MVC) is a pattern in software development that helps promote a clear separation of concerns and reusability of code.

The model is responsible for data persistence and management. The view is how that information is presented to the user via HTML, CSS, and JavaScript. The controller acts as an intermediary between the model and view, handling the routing, requests, and coordination of data flow. For this guide, we will focus on the model in MVC.

The model represents the database in our application. As developers, we want to be able to access these databases through code by implementing **object-relational mapping** via **Active Record**.

> Object-Relational Mapping (ORM) is the concept of using an object-oriented programming language (Ruby) to access relational databases (SQLite3).

> Active Record is an ORM framework represented as a Ruby gem. By abiding by its conventions, it allows us to simplify database configurations in Ruby-based applications.

A fundamental concept of ORM (and Active Record), is the mapping between models that represent object-oriented entities and database tables. We can view the model object as the database table and instances of that object as rows/records on that table. Following the logic, it makes sense to present the object’s attributes as table columns. In addition, every table has a column for the primary key ID that is unique to every instance. Depending on their association with other tables, they may include a foreign key ID as well. The foreign key is used to establish relationships between other tables.

The two most common ways tables relate to another is via a **one-to-many** or **many-to-many** relationship.

> One-to-many relationship is when one instance of a model connects to many instances of another model. A user can have many games so there is a one-to-many relationship between the User model and the Game model.

> Many-to-many relationship is when one instance of a model connects to many instances of another model and vice versa. A student can enroll in multiple courses and every course contains multiple students so this is a many-to-many relationship.

For example, if we want to create an app where users can browse a list of cities to see posts about that city, we can think about two models, City and Post. Each of these models can be represented as a table with each row representing a specific city or post. There is a one-to-many relationship between City and Post (a city has many posts and a post belongs to a city), which means that the posts table must have a foreign key that matches a primary key of a city.

## Getting started with Active Record

Steps:
1. [Set up Gemfile](#set-up-gemfile)
2. [Create models and associations](#create-models-and-associations)
3. [Create new migrations](#create-new-migrations)
4. [Migrate changes and check status](#migrate-changes-and-check-status)

### Set up Gemfile

The first thing we need to do is to make sure we have the [Rake](https://github.com/ruby/rake) and [Active Record](https://guides.rubyonrails.org/active_record_basics.html) gems included in the Gemfile. For more information on these gems, please visit the main website for each library.

Once the Gemfile is set up, run `bundle install` on the CLI to create Gemfile.lock.

### Create models and associations

When creating models, we need to have it inherit from ActiveRecord::Base. This gives our models access to commonly used methods for data manipulation. Within the class, we define its association with the other model. When using Active Record, it is crucial to use the correct conventions. When naming models, it must be singular and capitalized.

```
class City < ActiveRecord::Base
	# a city has many posts
	has_many :posts
end
```
```
class Post < ActiveRecord::Base
	# a post belongs to a city
	belongs_to :city
end
```

For a more comprehensive list of ActiveRecord::Base methods, please visit this [website](https://guides.rubyonrails.org/active_record_basics.html).

### Create new migrations

Once the models are created, we need to create the database using rake and migrations.

> Rake is a tool that allows us to automate certain tasks. By writing these task shortcuts inside Rakefile.rb, we can execute them using a CLI with quick commands.

> Migrations are an Active Record feature that provides version control for database changes. It produces a blueprint for database creation and manipulation.

To create a new migration, we run `rake db:create_migration NAME=<description_of_change>`. This will create a new migration file and defines a class of <description_of_change>  that inherits from ActiveRecord::Migration. It will automatically name the file with the datetime it was created.

In the case of our example, we would run `rake db:create_migration Name=create_cities` and then another for the Post model. Within the class, we write the code for the creation of our table. Here is how that looks:

```
class CreateCities < ActiveRecord::Migration[6.1]
  def change
    create_table :cities do |t|
      t.string :name
      t.string :population
      t.string :image
      t.string :country
    end
  end
end
```
```
class CreatePosts < ActiveRecord::Migration[6.1]
  def change
    create_table :posts do |t|
      t.integer :city_id
      t.string :category
      t.string :title
      t.string :body
      t.timestamps
    end
  end
end
```

We define a method `change` by invoking `create_table` (inherited from ActiveRecord::Migration) and passing in the table name. When naming tables, the word is in all lowercase and is pluralized. We map each attribute to a column by setting up its data type and name. We do not need to manually create the `id` column since it is automatically generated when adding a new record.

### Migrate changes and check status

Once we have our initial migration files, we can run `rake db:migrate` to execute the changes. Active Record will automatically run each migration file in order of creation and simultaneously create a schema.rb file. This is where we can check to make sure the tables are created properly with the appropriate columns.

Running `rake db:migrate:status` allows us to check the status of our migrations. It provides information about which migrations have been applied to the database. When a migration is marked as "up," it means that it has been successfully executed and applied to the database whereas “down” would mean it has not been applied or has been rolled back.

This way of version control allows developers to track the migration history and easily identify the current state of the database schema. By knowing which migrations have been successfully applied, developers can ensure that the database structure is up to date and consistent with the application's codebase. It provides a systematic approach to managing and applying changes to the database over time, making it easier to collaborate with other developers and maintain the integrity of the database schema across different environments.

### Next steps

Once we have created our models and corresponding database tables with columns defined, our next steps would be to seed the database and initiate the server. We can create seeds.rb, whose sole purpose is to fill our tables with data. Although we won't go over these in detail, there are some ways to achieve this.

1. Using randomly generated data via [Faker](https://github.com/faker-ruby/faker)
2. Grabbing data from a public API via [RestClient](https://github.com/rest-client/rest-client)
3. Scraping data from HTML via [Nokogiri](https://github.com/sparklemotion/nokogiri)

Finally, before we open our server, we must have our controller (in our MVC paradigm) set up. This middle layer dictates the communication between our client (view) and server (model). An easy way to do this is through [Sinatra](https://github.com/sinatra/sinatra), a web framework built on top of [Rack](https://github.com/rack/rack). Sinatra provides a simple way to set up our routes using a configuration file (config.ru) and the HTTP request handling file (application_controller.rb).

## Conclusion

Active Record, as an ORM framework, plays a crucial role in simplifying database interactions and promoting efficient development practices. Migrations provide a systematic approach to managing database changes, allowing developers to track the migration history and maintain the integrity of the database schema. With the ability to automate tasks using Rake and easily check the status of migrations, developers can ensure that their database structure is up to date and consistent. By mastering the fundamentals of Active Record and migrations, developers can enhance their productivity, collaborate effectively, and build robust web applications with ease.

> This guide is meant to serve as a learning tool for people who are just starting to learn Object-Relational Mapping. Please read from the official Active Record website for further detail. Thank you for reading and if you have any questions or concerns about some of the material mentioned in this guide, please do not hesitate to contact me at jjpark987@gmail.com.

## Resources

- [Active Record](https://guides.rubyonrails.org/active_record_basics.html)
- [Faker](https://github.com/faker-ruby/faker)
- [RestClient](https://github.com/rest-client/rest-client)
- [Nokogiri](https://github.com/sparklemotion/nokogiri)
- [Rack](https://github.com/rack/rack)
- [Sinatra](https://github.com/sinatra/sinatra)