Rails’ Active Record Basics

A library that enables Rails to create, modify and interact with tables in the database.

Table of Contents

Object Relational Mapping

Convention
Name
Schema

Overriding Convention

CRUD

Definition

Active Record is the M in MVC (Model-View-Controller), which is the layer responsible for representing business data (tables in database) and logic (code). — Official Rails Guide.

AR is a medium with which we can interact with the database

It provides an interface between tables in the database and Ruby program code (Active Record Objects or model) to modify or create attributes and instances of a table.

In context of the rails application, the Active Record Object are commonly referred to as models. In this article I will refer to Active Record Objects or model as objects and Active Record as AR.

ORM

Stands for Object-Relational-Mapping which is used by AR to access or modify data from a table in the database.

When talking about ORM, most people are referring to a library (example Rails) that implements ORM, because:

  1. O stands for Object, it refers to the programming language we use. In our example it is Ruby.
  2. R stands for Relational, it refers to a Relational Database Manager System, aka Database.
  3. M stands for Mapping, where it bridges between our AR objects and database.

When ORM isn’t used in an application, it uses SQL to manipulate with data in the database, which is sophisticated, time-consuming, it involves executing many queries such as:

  1. Create a database connection.
  2. Write the SQL query.
  3. Run SQL query in the database.
  4. And get data from the database.

Whereas with ORM applications such as Rails, we can interact directly with an object in the same language we’re using. We don’t need to write separate SQL statements (if using SQL database) to interact with the database for most purposes. In Rails, it doesn’t matter which type of database we’re using as long as we’ve set up the config/database.yml file properly. AR will handle all the nitty-gritty details of connecting our app with the database, even if we switch our database, we don’t need to change the application code, as it takes care of all the differences between databases so we can focus on the logic code that matters.

For more benefits of ORM, you can refer to this post.

Conventions

Naming Convention

By default, Rails will automatically pluralize the table name in the database depending on the name of the object declared. For example:

So if an object is of class Book, then its corresponding table name will be books.

If an objects’ name consists of 2 or more words, AdventureMovie, where each word is initialized by a capital letter, then in the database the words are divided by an underscore, adventure_movies.

And for the object named Person, its corresponding table name will be people. Naming convention in Rails just doesn’t add a suffix 's’ to any word but it's smarter than that.

So in summary naming convention for:
object 👉 Singular-CamelCase
table 👉 Plural-snake_case

Schema Convention

Just as AR uses a naming convention for names of a table in the database, similarly it uses for its columns/attributes too. There are certain names of an attribute that are reserved by AR to invoke certain functionality of it and it's not recommended to use these reserved names for other purposes. Those reserved names are:

id
By default, Rails will use this to uniquely identify each row or instance of a table. In other words, this is the Primary Key of a table. The data type of it will be an integer for SQL & SQLite and bigint for PostgreSQL & MySQL database. Rails will add this column by default when a table is created using AR Migration.

model_class_name’_id
Let's say we have 2 tables named, books and authors and we set up an association relationship between them. Both tables have a primary key, id, but in addition,books table will also have a column named author_id (foreign key), where each instance of it will refer to the id of authors table.
A foreign key isn’t set up by Rails automatically but only if we explicitly reference the relation in AR Migration. This is the attribute that AR will look for when we create associations between the tables.

created_at & updated_at
Rails will automatically create these attributes when the table is created in the database using timestamps method. The data type of these attributes will be of datetime. The time-value of created_at of an instance will be set only once at the time it was first created whereas for updated_at, time-value updates every time an instance is modified.

lock_version

type
Tells Rails that the object uses Single Table Inheritance (STI).

'association_name'_type
For Polymorphic Association.

'table_name'_count
It caches the number of belonging objects. Example: An author has many books. So in authors table, an attribute named as books_count will cache the number of books for each author.

These are the naming conventions of attributes adopted by Rails. If we follow these, it saves us from writing a lot of configuration code, hassle, and time, and in some cases no configuration to give at all! Hence, this is Rails’ Convention Over Configuration approach!

But Rails also provides the ability to explicitly configure in cases where we cant follow default convention.

Overriding Conventions

If you want an AR object or models’ name to be different than that required by naming convention, then in the model file we give:

class AdventureMovie < ApplicationRecord
#sets new table name
self.table_name = "my_adventurous_movies"
end

Same way, it's also possible to override the attribute name of a primary key, ‘id’ (which is the default), by:

class AdventureMovie < ApplicationRecord
#sets new primary key name
self.primary_key = "movie_id"
end

However, from changing id to movie_id, this won’t allow us to use another id attribute in the same table for a different purpose.

Do not use attribute names as that are listed under schema convention for any other purpose than that set by Rails.

CRUD

Stands for Create, Read, Update and Delete. These are the methods provided by AR which are created on the fly to read and manipulate the data stored in the table.

Create

For any model or object, to set a new instance or record in the table, there are a couple of ways:

.new
Instantiates an instance of the object, holds the data in memory until .save method is called.

# instantiates object
person_1 = Person.new(name: "Juzer", gender: "M")
#not saved yet, but available in memory
person_1
=> #<id: nil, name: "Juzer", gender: "M", created_at: nil, updated_at: nil>
#will save in database
person_1.save
=> #<id: 1, name: "Juzer", gender: "M", created_at: 2021-07-12 11:04:44 UTC, updated_at: 2021-07-12 11:04:44 UTC>

After person_1 is saved in the database, AR sets the value of id, created_at and updated_at attributes itself.

.create
Instantiates an instance and saves it instantly.

person_2 = Person.create(name: "Russell", gender: "M")
=> #<id: 2, name: "Russell", gender: "M", created_at: 2021-07-12 11:05:43 UTC, updated_at: 2021-07-12 11:05:43 UTC>

Read

There are many methods to access data:

# returns first instance in the table
first = Person.first
# extracts all the instances of female gender
females = Person.where(gender: "F")
# returns all the peoples details
all = Person.all
# extract data of an instance whose name is "Juzer"
juzer = Person.find_by(name: "Juzer")

….for more of these methods you can refer to the AR Query Interface guide.

Update

Updates existing data:

russell = Person.find_by(name: "Russell")
russell.name = "Russell Fernandez"
russell.save

To update multiple attributes at once:

russell.update(name: "Russell Fernandez")

To update data of several instances at once:

Person.update_all(relationship: nil, birth_date: nil)

Delete

To destroy an instance from a table:

juzer = Person.find_by(name: "Juzer")
juzer.destroy

To destroy multiple instances:

# deletes all records of Male gender 
Person.destroy_by(gender: "M")

To destroy all users:

Person.destroy_all

More of AR

There are tons of features provided by AR and the above discussed is just the tip of the iceberg. Features such as:

  1. Switching between different databases with ease:
    Able to use MySQL in the development environment and PostgreSQL in production. Setup includes a couple of steps. Add required gem in Gemfile, run bundle install and configure the config/database.yml file accordingly.
  2. Migration:
    Enables to create, modify and delete tables from the database.
  3. Associations:
    Enables connection between 2 or more models or objects.
  4. Validation:
    Enables to validate a particular attribute of each instance before saving it to the database. Methods such as save, create, update etc will return false if any of the validation of the attribute fails.
  5. Callbacks:
    Enables to add certain behavior to models when those events occur such as creating, updating, or deleting instances of a table.

Jr. Ruby on Rails Dev | Math Enthusiast | Ex-Machine Learning Engineer | https://juzershakir.github.io/