Active Record Models and Rails
Last updated
Last updated
Active Record is the built-in ORM that Rails utilizes to manage the model aspects of an application. What is an ORM? An ORM is an Object Relational Mapping system, essentially this is the module that enables your application to manage data in a method driven structure. This means that you are able to run queries, add records, and perform all of the traditional database processes by leveraging methods as opposed to writing SQL manually. For example, below is the traditional way that we would query a database of 'posts' using SQL:
Compared with leveraging Active Record:
By using Active Record, you are also able to perform advanced query tasks, such as method chaining and scoping, which typically require less code and make for a more readable query.
So if we have a database table, why do we need a model file? By using model files, we are able to create an organized layer of abstraction for our data. An important thing to remember is that at the end of the day the model file is a Ruby class. It will typically inherit from the ActiveRecord::Base
class, which means that it has access to a number of methods that assist in working with the database. However, you can treat it like a regular Ruby class, allowing you to create methods, data attributes, and everything else that you would want to do in a class file.
A typical model file will contain code such as but not limited to the following:
Model instance methods
Default settings for database columns
Custom algorithms
If any/all of the items above aren't familiar to you yet, don't worry. We'll cover them in future lessons. It's important to have an idea of what can be included in a model file, even at this early stage.
In order to get started, we will first create an RSpec test. We've provided a basic skeleton of a Rails application using RSpec in this repo.
To generate this app, we installed the Rails gem, then ran
Let's create a new file: spec/models/post_spec.rb
. In that file, place the following code:
If we run bundle exec rspec
, it will throw an error since we don't have any code in the application for our Post
model yet. To fix this, create a new file in the app/models
directory called post.rb
, and add the following code:
This will get the tests passing, but it still has some weird errors because we need to create a schema file. You can do that by running rake db:migrate
. (There is no need to create a database with rake db:create
first. The test suite will create a test database for us when we run our tests.) This will create the schema file and clear the warning. Now update the Post
spec to test for a Post
being created. It should look something like this:
Running this test gives us the error of: undefined method 'create!' for Post:Class
. To implement this feature, let's create the database table for our posts. Create a new directory in the db/
directory called migrate
, and add a new file called 001_create_posts.rb
. To that file, add the following code:
The timestamp also plays a role in making sure that only new migrations run when we run rake db:migrate
. The db/schema.rb
file is updated with a version number corresponding to the timestamp of the last migration you ran. When you run rake db:migrate
again, only migrations whose timestamps are greater than the schema's version number will run. So, the numbers at the beginning of the filenames of your migrations are required so ActiveRecord can be sure to run each of your migrations just once and in the proper order.
After running rake db:migrate
we can see that our db/schema.rb
file has been updated with our new posts table. However, if we run our tests again we will still see them failing due to the same error: undefined method `create!' for Post:Class
. This is because we left out one very important piece of code from the Post
model. In order to leverage built-in methods such as .create!
, we need to have the Post class inherit from ActiveRecord::Base
. Update the post.rb
model file to match the following:
Now all of the tests are passing and we can create a new post correctly. Even though we know this is working because our tests are passing, let's still test this in the console. Open up the Rails console by running rails console
. Running the console will load the entire Rails environment and give you command line access to the app and the database. The console is a powerful tool that you can leverage in order to test out scripts, methods, and database queries.
Once the session has started, run the following command to ensure it recognizes our new Post model:
If everything is set up properly, you will see that it returns an empty Active Record object. Let's test creating a record using the console:
Now run the query:
It returned our newly-created post!
With our Post
model working, let's add a new feature that returns a summary of a post. As usual, start off by creating a spec for the feature:
If we run this, we'll get a failure since we do not have a post_summary
method for Post
. Add that to the model file:
This now results in a failure since the method currently doesn't return anything. Update the post_summary
method as follows:
Now if you run the tests, all of them are passing and our Post
model has an instance method that returns a post summary. You can test this out in the Rails console as well by running a query on the record we created, such as:
It should return the summary value of the last post we created: "My title - The post description"
.
As you may have noticed, we did not have to create a controller, route, view, etc. in order to get the Post
model working. The data aspect of the application can work separately from the view and data flow logic. This level of abstraction makes it efficient to test data behavior without having it strongly coupled to how it is rendered to the user. With that being said, it is considered a best practice to have your controller and view files follow the proper naming convention so that the MVC associations are readable. For example, to build out the controller and view code for our Post
model, we would create the following structure:
Create a posts_controller.rb
file that calls on the Post
model
Create a views/posts/
directory that stores the views related to the Post
model
Also, if you are coming from other programming languages you may be wondering how exactly we are able to connect to the database automatically without having to create connection strings. The reason for this simplicity resides in the config/database.yml
file that was generated when we created our application and ran rake db:create
. In that file, you will see that the development, test, and production databases are all configured. From that stage, the ActiveRecord::Base.connection
method connects your application to the database, which is another benefit of having our model classes inherit from the ActiveRecord::Base
module.
Being able to work in different environments is one of the strong points of Rails, and the database.yml file takes advantage of this feature by having different database options for each type of environment. If you take a look at the file, you can see that you can establish different database adapters, pools, timeout values, etc. for each environment specifically. This allows for you to have a setup such as using SQLite locally and Postgres in production, along with having a segmented database environment for your testing suite. Some of these items are components that you won't need until you get into more advanced applications. However, it's good to know where these items are located in the file system for when you get to that point. Essentially, this file includes a lot of stuff you will rarely have to handle, but just remember that if anything requires database configuration it will be here.
We covered quite a bit of material in this lesson. You should now have a firm understanding of Active Record models in Rails. Active Record is a powerful tool that enables developers to focus on the logic of their applications while streamlining processes such as connecting to the database, running queries, and much more.
As a professional Rails developer, you will be expected to build applications by leveraging a process, so we will walk through how to build each feature with a test-first approach so that the tests can lead our development. However, please focus on the implementation code so that you can get a firm understanding of how to build a model, database table, etc.
This is a basic migration that will create a posts
table that will have title and description columns, along with the built in timestamps. For a refresher on migrations, see . This migration follows the standard naming convention. When you want to create a table, the migration's class name should reflect that; hence, CreatePosts
. This is then reiterated by the :posts
argument passed to the create_table
method. The filename itself needs to be unique, and when you generate a migration automatically through a model or scaffold generator you will notice that the migration file name is prepended with a timestamp value to make sure that we can run migrations in the order they were written.
Clone repo here: