Rails’ Active Record Basics
A library that enables Rails to create, modify and interact with tables in the database.
Table of Contents
↦ Convention
↪ Name
↪ Schema
↦ 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.
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:
- O stands for Object, it refers to the programming language we use. In our example it is Ruby.
- R stands for Relational, it refers to a Relational Database Manager System, aka Database.
- 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:
- Create a database connection.
- Write the SQL query.
- Run SQL query in the database.
- 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.
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:
- 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, runbundle install
and configure theconfig/database.yml
file accordingly. - Migration:
Enables to create, modify and delete tables from the database. - Associations:
Enables connection between 2 or more models or objects. - Validation:
Enables to validate a particular attribute of each instance before saving it to the database. Methods such assave
,create
,update
etc will returnfalse
if any of the validation of the attribute fails. - Callbacks:
Enables to add certain behavior to models when those events occur such as creating, updating, or deleting instances of a table.