- Read Tutorial
- Watch Guide Video
This guide explains how to work with the Rails model generator, specifically it shows how you can generate models and use the model to query the database and render data onto the view.
Let’s get started by going to the project management dashboard, and checking off the task called "Controller generator for site pages".
Our next task is the ‘model generator for list of skills’. I opened my own portfolio to show you what I mean when I say a list of skills. I'm thinking something along these lines.
It is my intention for you to list each of the languages you work with as a skill, followed by the percentage of time you spend working in each category. The percent should total up to 100.
As I said, this gives the amount of time I spend daily on each of these skills. If you're following along building your own portfolio page, you don't have to add the percentage values to your site. I personally like to because there are some cool visuals I can implement with it. For some people though, percentage values can be a little ambiguous, and if you're one such person, feel free to skip it. Mostly, I wanted to show you this so you would understand the attribute values that I'm going to utilize as we create this functionality.
Let's come to the terminal. We will create a new branch for our new feature. Remember the code for creating a new branch is git checkout -b < branch-name >
We're going to name it 'model-generator', so the command will be git checkout -b model-generator
. You should get a response that you have Switched to a new branch ‘model-generator’
The Model Generator
Now, let's run our model generator. If you are thinking we will use the key work model, you are correct. The command is
rails g model Skill title:string percent_utilized:integer
Remember, we had the scaffold generator and the controller generator before, so this is going to be our model generator. Like the controller generator, our model generator is also lightweight, however the model generator focuses solely on the model. It will not create any views, it will not have it’s own controller, nor will it create any routes.
Take note, I used the singular word Skill
while creating the model. It is a Rails convention to have the model name in singular form and your controllers in plural.
Another item to note is that when generating the controllers, we passed the names of the pages we wanted, but with scaffolds and models, which are items that have to do with the database, we are required to pass the attributes and their respective datatypes.
Here in this instance, we are passing two attributes. First, title
which is a string data type and second, percent_utilized
, an integer data type. You can also use the decimal data type if you like, but I don't want to get so granular with numbers here.
I considered using ‘percent’ for the second attribute name, however, I usually like to give very clear names to my attributes and methods to make it easy for others to understand my code. Or for that matter, even myself, when I go back and look at the code later on.
Let's take a look at what this created for us. First, it invoked active_record
, which is the ORM. Do not worry if you've never heard of ORM, as we'll get into it much later. The generator also created a migration file and a model file. The model generator is by far the most lightweight generators. If you remember, our controller generator was much more lightweight than scaffolds, and models even more so.
Open your sublime editor and navigate to the models
file. Here, you should see the skill.rb
model file. Go ahead and open it.
class Skill < ApplicationRecord end
You can see the skill class here. It inherits from ApplicationRecord
. We have an entire section dedicated to active_record
and ApplicationRecord
and working with data, so I'm not going to go deep into it. Just note that this has a direct connection with our database.
Notice, we have no new items in our view. We can close that directory for now, and close the app directory as well That will make it easier to locate the db (database) directory.
Now, go to db/migrate
and here, you should see the migration files. There are, in fact, two here. The first one was from our scaffolds and the second one is for the new model generator. Open the skills migration, and it should look like this:
class CreateSkills < ActiveRecord::Migration[5.0] def change create_table :skills do |t| t.string :title t.integer :percent_utilized t.timestamps end end end
If you compare both the migration files, they essentially do the same thing. Just like the scaffold created a new table called Blogs, and passed in the title and body items, our model generator created more or less the same thing.
For example, you have a ruby class called CreateSkills
that inherits from ActiveRecord::Migration—a database migration. This class has a method called change
, and if you run this, it will create a table called skills
and pass the values of title
as a string, and percent_utilized
as an integer. It also has a field called timestamps
.
If you go to the schema.rb
file, you'll see that it's not updated yet as it still has only the blogs
table. So, let's migrate our database.
In your terminal type the command rails db: migrate
Essentially, migration files change the schema of the database. Our migration file can be seen as the set of instructions needed to change the database, and this command simply follows these instructions and makes the necessary changes to update the file.
The Database
Remember we installed the postgres database? If you look in your status menu, top left of your mac screen, you will see it is running. It contains a series of database tables. Simply put, a table is file you can run your queries on and get the data you want.
When we gave the rails db:migrate
command, it went and updated the database. It created a table for us with the attributes we specified in the migration file.
Now if you go back to the schema.rb
file, this is what you'll see.
ActiveRecord::Schema.define(version: 20170313003558) do create_table "blogs", force: :cascade do |t| t.string "title" t.text "body" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "skills", force: :cascade do |t| t.string "title" t.integer "percent_utilized" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
You can see a table called skills
. This is an empty table, so let's see how we can add items to it.
Rails Console
Go to your terminal, and I want you to type in something new: rails c
This is the short-form for rails console. The console is a direct connection to the database, so from here, we can run methods, scripts and all the kinds of things we would do in our code in our application, but we also have a direct connection to the database.
To create a new ‘Skill’ in our database, the command is
Skill.create!(title: "Rails", percent_complete: 75)
In this instance, the symbol "!" is called a bang. When we use it in the console, it will throw an error if I make a mistake, like typing the wrong type of data or the wrong attribute. For example, if I typed title
and percent
as attributes, the bang will throw an error because our fields are title
and percent_utilized
. If I don't have the bang, it will still fail, but silently (ie with no error message).
The simple reason you use create instead of create! in your production applications is that if someone makes a mistake, you don't want it to crash the entire system. Instead you'd want the method to fail silently, so you can catch the issue and fix it. Typically, you'll include validations to catch this type of error, and we'll cover validations later in the course.
So, if we run the above code, guess what? It will fail! I used the wrong attribute name.
Now, you know why we did the exclamation mark! The console even tells us the cause of failure. In this way, Rails is fantastic at giving you clear and concise error messages. Though it may look overwhelming when an error happens, if you look at the top portion of the error message, the cause should be clear.
Here the error reads ActiveModel::Unknown AttributeError: unknown attribute ‘percent_complete: 75.
So, we know there is an issue with our model because it references ActiveModel. You could simply look at the Skill
table and check for percent_complete
attribute to determine why it was unknown to Rails. We can quickly see we used the wrong attribute name.
So, let's change the attribute to percent_completed
, and run it again. It's still throwing an error!
Oh! and that's because the attribute is percent_utlized
. The correct command to create a new skill in this table is:
Skill.create!(title: "Rails", percent_utilized: 75)
With that line of code we are creating a record in our skills
table.
I can do this multiple times, one for "HTML" with a percent_utilized
value of 5. That command is
Skill.create!(title: "HTML", percent_utilized: 5)
and another for "Angular" with a percent_utilized
value of 10:
Skill.create!(title: "Angular", percent_utilized: 10)
Now, to see all the records we created, the command is
Skill.all
Remember our controller for Pages
? There we had code like this:
@posts = Blogs.all
Just asSkill.all
will bring up all the records from skills
database. I can also run Blogs.all
here in the console and this will return all the blogs for me. Essentially, these are database queries.
Now, if we exit out the of the console command + d
, and start the rails server rails s
, we can walk through the process of how to call this data in our application.
Let's go to our pages_controller.rb
. Looking at our home action, we see there is already a call for posts. We can add another line of code for our skills, like this: @skills = Skill.all
. Our pages controller should now look like this:
class PagesController < ApplicationController def home @posts = Blog.all @skills = Skill.all end def about end def contact end end
Save the file and then we'll go to app/views/ and open home.html.erb
. Here we can create another Ruby code block to display skills:
<%= @skills.inspect %>
For easy readability, let's have a header for each display.
<h1>Blog Posts/</h1> <%= @posts.inspect %> <h1>Skills</h1> <%= @skills.inspect %>
The way this displays will be very unattractive. .inspect
shows the object for what it is worth. It shows the class it belongs to, the attribute titles, everything like that. Eventually I will show you how to call this data so it fits in with our design.
If you go to your home page now, and refresh it, you should be able to see both Blog Posts and Skills.
So, everything is working properly!
Repetition and Thoughtfulness
Though some of this may sound repetitive, that is actually good thing, because the more times you see, hear or read it, the more it is going to make sense and the more you will see how easy it is to send data from the model to the controller and then to an actual view.
I'm purposefully picking on the home page and sending a lot of data to it because many students wonder how to get data out of the world of scaffolds and into another area of their app. In general, it makes sense to display blog values on a blog page. However, many new students have asked me how to display data from one controller on another. We just went through the process of doing that:
You can call the model from within your controller, and make the instance variable available to the corresponding view file.
Another way to Merge a Branch
Finally, let's get this work on GitHub, and this time, I'm going to show you a different way of merging branches.
When you type git status
, you can see all the changes we made.
Next, add all the files git add .
And now commit them with the message git commit -m ‘Integrated skills via model generator’
.
Instead of pushing this branch directly to Github like we did last time, I’m going to show you how to merge from the command line.
First, checkout the master branch with the command git checkout master
.
If you're wondering why I'm merging from the command line, it's because it is faster and I prefer to use this method when I'm working on a solo project.
Next, type the command git merge model-generator
That last imperative has actually merged our feature branch into the master branch. You should see in your response that there were 5 files changed, 26 insertions (+) 2 deletions (-)
If you type a git branch
command you should see you are on *master.
If you switch back to the code, you'll see all of our new code is still there.
Lastly, push everything up to GitHub with the command git push
.
If you go to the GitHub website, you should be able to see that your repository was updated a minute ago.
If you navigate to app/models/skill.rb you will be able to see the model we just created, and be assured everything we just did is on the master branch.
If you're working with a team, using the pull request method is the traditional and best way to merge git branches. However, if you're working alone, it's a little bit faster to merge from the command line and then push to the repo.
So, you now know how to work with model generator in rails.