Rails Guide — Part 4 Database Models
In our previous blog we talked about how a Rails controller acts similar to an intermediary between the routes, models, and views. Today we will look at the model component inside of a Rails application.
In the simplest terms, a model is a table within our database. Such model can have different columns, two or more models can be linked via a shared column, you can define custom scopes inside of the model and have the controller utilize it, etc.
Looking at our app from before. It has a single model named Book. And from the schema.rb file, we can see it has three columns (title, audience, isbn) that we created, as well as two columns (created_at, updated_at) automatically brought in by Rails.
It was created using a Rails model generator from our last blog with this syntax in the Terminal:
rails g model Book title:string audience:string isbn:integer
We can also manually create a model In the app/models folder, let’s create an author.rb file, it will be a class of Author that inherits from ApplicationRecord.
The second part is creating the actual table. We can run a migration command again:
rails g migration create_authors
Run rails db:migrate to create the authors table. We can check our schema.rb file to make sure everything is as planned:
We can add columns to our model with migration files. If we want to add a name column to it, in the Terminal, we can run the command:
rails g migration add_name_to_authors name:string
This creates a migration file inside of the db/migrate folder.
Running rails db:migrate in your Terminal will add the name column to the authors table.
Similarly we can delete columns with the command:
rails g migration remove_name_from_authors name:string
Simply delete the migration file if you change your mind. Make sure the migration has not been ran yet with rails db:migrate
Rails also gives a powerful generator option to create a model, table and column migrations with a one line command, so you don’t have to create a model, create a table, add individual columns one by one. Suppose we were to create a publisher model with a name column. We can run:
rails g model Publisher name:string
One of the most common tasks you will perform in a model is to connect tables together with helper methods. Suppose we want to achieve the following relationship amongst our three models:
An author will have many books. And a publisher will have many books. (Ignore the fact that a book might be written by multiple authors for now) In a one-to-many relationship like this, it’s the job of the sub model to keep track or have a column that holds a reference to the super model.
To add such column in the Book model, we can utilize a migration again:
rails g migration add_columns_to_books author:references publisher:belongs_to
Notice references and belongs_to accomplish the same thing. There’s no difference between the two.
Running rails db:migrate again. We can see the columns are added in.
We can now create books with both author and publisher id associated with them. In real life scenarios we might want to query the books from a particular author or publisher. Instead of using a loop, Rails gives us some useful helper methods.
Inside of the author.rb and publisher.rb files, we can call the has_many method:
From the book perspective, we can also query a book’s author or publisher with a helper method:
We can even connect author and publisher through the joiner table book. Imagine the author M Aquino has written 3 books: “Analysis of Hash Tables” with a publisher of “Geek Culture”, “Binary Heaps” with a publisher of “Nerd for Tech”, and “Data Visualization with Plotly” with a publisher of “Geek Culture”.
If we were to query all M Aquino’s books’ publishers, the long way would be to find all his books, then from the books, pull out all the publishers associated with the books. But in Rails, we can do all of these with a one liner:
Let’s update our seeds.rb file and see everything in action in Rails console.
Our book object is now expecting an author_id as well as publisher_id, let’s put those in. We can reset our seeds.rb file with the command:
In the Rails console, run a few simple commands such as Author.first, Book.count to make sure everything is seeded correctly.
Now let’s try out the helper methods. Here I created a variable called aquino and store Author.first into it. By simply calling aquino.books and aquino.publishers, the database is able to pull out all respective information back to me!
We will take a look at what more we can do in the model such as validations for our data, custom scopes, and model concerns in the coming week! See you!