Mastering Models in Ruby on Rails 7: Generators, Migration, and CRUD Database Query

Shah Nawas Khan
7 min readAug 15, 2023

The following lesson in this blog post is also available for FREE in the VS Code. Download the latest version of Code Zoomer from your VS Code Extension Marketplace.

Code Zoomer is a VS Code extension that can get you started quickly to learn a specific subject in coding with Rails. Here are some benefits of using the extension:

  • You don’t have to create the Ruby on Rails project from scratch.
  • Copy and paste the code snippet provided into the specified source file in the lessons with ease.
  • Run Terminal and Rails Console commands provided in the lessons with a click of the Run button on the lessons page.

You can certainly cover this same lesson quicker using Code Zoomer, otherwise, let’s continue to the lesson below.

Overview

In Ruby on Rails, models are Ruby classes that represent database tables. Models handle the communication between the application and the database and provide an object-oriented interface for working with data. In this lesson, we’ll cover the basics of working with models and databases in Ruby on Rails.

Getting started

This lesson has a started repository that you can clone into your development machine and continue to learn these lessons. To clone the repository use the following command:

git clone  -b 101 --depth 1 https://github.com/shahnk19/my-rails-lesson.git

This command would clone the lesson repository at the correct `tag` to get you started in this particular lesson.

If you used the Code Zoomer extension in VS Code, you can clone and load the correct repository code with a click of a button for each lesson.

Creating Models

To create a new model in Ruby on Rails, use the `rails generate` command followed by the model name and its attributes. Open your terminal and run the following command:

rails generate model User name:string email:string

The `rails generate` command above generates several files as shown below:

invoke active_record
create db/migrate/<timestamp>_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml

A new model called `User` is created with two attributes: `name` and `email`, both of type `string`. All model classes would be created in the `app/models` folder in your application. Open the model you just created in `app/models/user.rb` as shown below.

class User < ApplicationRecord
end

The newly generated `user` models shown above may look empty, but it already has all the functionality you need to work with the `user` table. This rich functionality is provided by the Rails library called Active Record, which is provided by the inherited class `ApplicationRecord`. This is why even an empty class like the above can be used to query or manipulate data on the `User` table in the database.

We will see more about manipulating the `user` records later, but now, let’s first look into creating our `user` table in the database.

Database Migrations

Database migrations are Ruby scripts that describe changes to the database schema. Migrations allow you to make changes to the database structure without having to manually update the database.

When you ran the `rails generate` command above, it would also generate a database migration file in the `db/migrate` directory with a name like `20230306071626_create_users.rb`. Don’t worry if the numbers in the file name don’t match, as it corresponds to the timestamp when you ran the generate command. The timestamp is in the format `YYYYMMDDHHMMSS`.

Let’s take a look at the contents of your new migration file:

class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end

The above script would create the `user` table after it was run. The `user` table would be created with two columns you have specified in the `rails generate` command, that is the `name` and `email`. Additionally, it has automatically added the code to include `timestamps` in the table. This convenient feature would create two additional columns named `created_at` and `updated_at` in the table. Another column that is not specified in the code above, but would be added by default in this migration is the `id` that uniquely identified each record.

Before running the migration, let’s first check the state of the current database and its migrations using the commands below:

rails db:migrate:status

Since we have not run any migration yet on this project, you would get a message `Schema migrations table does not exist yet.`. Now, let’s run this migration.

rails db:migrate

You should see the output of the command below, indicating that the table has been created.

== 20230306071626 CreateUsers: migrating ======================================
- create_table(:users)
-> 0.0018s
== 20230306071626 CreateUsers: migrated (0.0019s) =============================

We can run the `rails db:migrate:status` command again now to check the state of the migration. Now that we already ran our first migration, you should see output similar to below:

Status Migration ID Migration Name
- - - - - - - - - - - - - - - - - - - - - - - - -
up 20230306071626 Create users

The result above shows that we have one migration to `Create users` was applied, as indicated by the status `up`. If the status is `down`, it indicates that the migration is pending and has not been applied yet. Also, notice the Migration ID is derived from the autogenerated `<timestamp>` value on the migration file name.

Oh, we forgot one thing. Some of the users can be an admin, this means our `user` table must also have another `boolean` column to flag if the user is admin. If the creation of the `user` table is not released yet, you could just edit the previous migration file to add that `admin` column. But let’s see how we can do such changes to the database table after it was released to production.

First, we need to create a new migration using the `rails generate` command followed by the migration name:

rails generate migration AddAdminToUsers admin:boolean

This creates a new migration file called `add_admin_to_users.rb`, which contains the following code:

class AddAdminToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :admin, :boolean
end
end

This migration adds a new column called `admin` to the `users` table, of type `boolean`.

Now, try to run the `rails db:migrate:status` command again to check the status of our database and migration. You should see that you have one migration with `up` status and a new migration with a `down` status.

Status Migration ID Migration Name
- - - - - - - - - - - - - - - - - - - - - - - - -
up 20230306071626 Create users
down 20230306081303 Add admin to users

Let’s run migrations and update the database using the `rails db:migrate` command. Now our database should have the `user` table applied with a new column called `admin`.

CRUD Operations

CRUD stands for “Create, Read, Update, Delete”. In Ruby on Rails, you can perform these operations on models using the following methods:

# Create a new user
max_payne = User.new(name: "Max Payne", email: "max.payne@codezoomer.com")
max_payne.save
# Read a user by email
max_payne = User.find_by(email: "max.payne@codezoomer.com")
# Read a user by id
max_payne = User.find(1)
# Update a user
max_payne.update(name: "Max Payne Two")
# Delete a user
max_payne.destroy

Now that our database is properly set up, we can try to play with our `user` model using the `rails console`. The console is an interactive coding environment that has rails and our application code loaded, so we can interact with the code in the terminal.

You can launch the console with the `rails console` command in your terminal (you can also use a shorthand for this by running `rails c`). In this tutorial, the terminal is automatically created for you, so you just have to click the `Run` button for each command. To open this terminal, click the label `Rails Console` in the code block below:

rails console

Now you should see a prompt, in your terminal as shown below.

Loading development environment (Rails 7.0.3)
3.1.2 :001 >

First, let’s check how many user records we have in the `user` table by entering `User.count` into the prompt. You should see the console to output the `SQL` command it ran to `SELECT COUNT(*) FROM “users”` and returns `0`. We would run this code again after creating a new user.

At the prompt, run the following command to create a new user.

max_payne = User.new(name: "Max Payne", email: "max.payne@codezoomer.com")

What this code does is only initialize a user object into the variable named `max_payne`. You can test this by running the `User.count` command again to check if the new user is created now. The user is only created in the database when we save this user by entering the below code into the prompt:

max_payne.save

After running the above code, you should see your console shows the `SQL` command output that was run on your database.

TRANSACTION (0.1ms) begin transaction
User Create (1.5ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Max Payne"], ["email", "max.payne@codezoomer.com"], ["created_at", "2023–03–06 08:36:25.048875"], ["updated_at", "2023–03–06 08:36:25.048875"]]
TRANSACTION (0.8ms) commit transaction
=> true

The console output shows it has run the `INSERT INTO` SQL command to create your first user record. Let’s check now if we have the records created in the `user` table now. Type `User.count` in the prompt and check how many records we have in the `user` table. It now should show that you have `1` record.

The `User` class comes with rich functionality to manipulate its corresponding `user` table in the database thanks to Active Record Rails library.

You can now play around with the record to test the other CRUD functions to `read`, `update`, and `delete` the records.

Querying the Database

Apart from the CRUD functions, you can also query the database using the `where` method. For example, if you want to find all the users who are `admin` then you can run :

users = User.where(admin: true)

This returns a collection of all users where the admin attribute is true.

Conclusion

In this lesson, we covered the basics of working with models and databases in Ruby on Rails. We learned how to create models, migrate the database, perform CRUD operations, and query the database. There are more advanced functions you can do with the models of your database, however, what you have learned in this lesson should be enough for you to build models for any CRUD application on Ruby on Rails.

If you like this lesson, there are more lessons like this in the Code Zoomer VS Code extension where you can work in simple and easy-to-follow tutorials for a specific subject building real-life projects.

Other tutorials in the same series you might be interested with:

  1. Setting up Ruby on Rails developer’s machine
  2. Mastering Models in Ruby on Rails 7: Generators, Migration, and CRUD Database Query
  3. Mastering Views in Ruby on Rails 7: DRY, Partials, Layouts, and Hotwire Stimulus Unleashed

--

--

Shah Nawas Khan

I am a computer programmer, loves to learn and teach. I created Code Dryer to help developer save time from doing boring stuff. https://www.codedryer.com/