Introduction to ActiveRecord Models

This is a step by step guide to create, update and test ActiveRecord models. For detailed information please refer to Rails Guides.

Now that you know how to get up and running with Ruby (and Rails) from the article 4.5 Ways to Install Ruby in Userspace, that means you are ready to start dealing with Rails and its features.

ActiveRecord is a gem that comes with Rails and is responsible for storing, updating, deleting, validating, and querying the database.

Out of the box Rails is already prepared to use it, so if you start a project like:

%  rails new my-blog

It will be completely prepared to use ActiveRecord. Generate the project with the command line above and let’s get started.

Generating the models

There are many ways to generate ActiveRecord models and here’s one. Create a model called Post using the rails generate command:

%  rails generate model Post title body:text published_at:datetime

This command will create:

  • One model in app/models/post.rb;

  • One migration in db/migrate/xxxxxxxxxxxxxx_create_posts.rb (xxxxxxxxxxxxxx is the timestamp I will talk about it later);

  • Some tests within the tests directory;

In Rails 5 the model is like:

class Post < ApplicationRecord
end

I’m using Rails 5 for this post, but if you are using Rails 4:

class Post < ActiveRecord::Base
end

Playing with the model

ActiveRecord::Base is responsible for adding some methods to your model. I will show some of them:

1.The first one is table_name:

% rails c
Running via Spring preloader in process 5751
Loading development environment (Rails 5.0.0.1)
>> Post.table_name
=> "posts"

Look at the file db/migrate/xxxxxxxxxxxxxx_create_posts.rb:

class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.datetime :published_at

      t.timestamps
    end
  end
end

And look at the model again:

class Post < ApplicationRecord
end

You will notice that there is not any, ANY configuration in the model about what table it uses, it is all about convention over configuration. You will see a lot of things like that.

2. new_record?, persisted?, and save.

Exit the previous rails console with exit and run:

%  rake db:migrate
== 20160916004714 CreatePosts: migrating ===========================
-- create_table(:posts)
   -> 0.0064s
== 20160916004714 CreatePosts: migrated (0.0066s) ==================

And in rails console again:

%  rails console
Running via Spring preloader in process 31021
Loading development environment (Rails 5.0.0.1)
>> post = Post.new(title: 'Testing', body: 'The body here', published_at: Time.new(2015, 12, 31, 1, 2))
=> #<Post id: nil, title: "Testing", body: "The body here", published_at: "2015-12-31 04:02:00", created_at: nil, updated_at: nil>
>> post.new_record?
=> true
>> post.persisted?
=> false
>> post.save
   (0.2ms)  begin transaction
  SQL (0.6ms)  INSERT INTO "posts" ("title", "body", "published_at", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["title", "Testing"], ["body", "The body here"], ["published_at", 2015-12-31 04:02:00 UTC], ["created_at", 2016-09-16 01:02:48 UTC], ["updated_at", 2016-09-16 01:02:48 UTC]]
   (128.8ms)  commit transaction
=> true
>> post.new_record?
=> false
>> post.persisted?
=> true
>> post.id
=> 1

When an object is not stored in the database, new_record? returns true and when the object is stored in the database persisted? returns true.

And I can update the model too!

%  rails c
Running via Spring preloader in process 2565
Loading development environment (Rails 5.0.0.1)
>> p = Post.find(1)
  Post Load (0.4ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Post id: 1, title: "Testing", body: "The body here", published_at: "2015-12-31 04:02:00", created_at: "2016-09-16 01:02:48", updated_at: "2016-09-16 01:02:48">
>> p.published_at = '2015–11–30 02:03'
=> "2015–11–30 02:03"
>> p.save
   (0.2ms)  begin transaction
  SQL (0.6ms)  UPDATE "posts" SET "published_at" = ?, "updated_at" = ? WHERE "posts"."id" = ?  [["published_at", nil], ["updated_at", 2016-09-16 01:06:48 UTC], ["id", 1]]
   (159.7ms)  commit transaction
=> true
>> Post.find(1).published_at
  Post Load (0.2ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> nil

I recommend that you play a lot with rails console because for me it is one of the most powerful tools I use to try some code snippets, to debug, or to check anything I need to.

As an exercise try to learn how to use update in rails console by reading update (ActiveRecord::Persistence) — APIdock.

Validation

Sometimes you want your user to always fill some attributes, in this section we will see how to require them.

Create a model only with the body:

%  rails console
Running via Spring preloader in process 4609
Loading development environment (Rails 5.0.0.1)
>> Post.create(body: 'This is the body')
   (0.2ms)  begin transaction
  SQL (0.9ms)  INSERT INTO "posts" ("body", "created_at", "updated_at") VALUES (?, ?, ?)  [["body", "This is the body"], ["created_at", 2016-09-16 01:08:25 UTC], ["updated_at", 2016-09-16 01:08:25 UTC]]
   (141.7ms)  commit transaction
=> #<Post id: 2, title: nil, body: "This is the body", published_at: nil, created_at: "2016-09-16 01:08:25", updated_at: "2016-09-16 01:08:25">

And now update your model so it will look like:

class Post < ApplicationRecord
  validates :title, presence: true
end

In order to verify what behavior this line yields in the model open the rails console.

Before it:

%  rails c
Running via Spring preloader in process 5606
Loading development environment (Rails 5.0.0.1)
>> post2 = Post.find(2)
  Post Load (0.3ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
=> #<Post id: 2, title: nil, body: "This is the body", published_at: nil, created_at: "2016-09-16 01:08:25", updated_at: "2016-09-16 01:08:25">
>> post2.valid?
=> true

And reloading our console (#protip here :):

>> reload!
Reloading…
=> true
>> post2 = Post.find(2)
  Post Load (0.3ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
=> #<Post id: 2, title: nil, body: "This is the body", published_at: nil, created_at: "2016-09-16 01:08:25", updated_at: "2016-09-16 01:08:25">
>> post2.valid?
=> false

I recommend that you read Active Record Validations — Ruby on Rails Guides to learn more about the validations.

Relations

Create another model called Author:

%  rails generate model Author name
Running via Spring preloader in process 5165
      invoke  active_record
      create    db/migrate/20160919233111_create_authors.rb
      create    app/models/author.rb
      invoke    test_unit
      create      test/models/author_test.rb
      create      test/fixtures/authors.yml

If you wonder what is that number in the migration (like 20160919233111), you can see IT as “the order to run the migration”.

To figure it out we can recreate our database:

%  rake db:drop && rake db:create
Dropped database 'db/development.sqlite3'
Database 'db/test.sqlite3' does not exist
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'

And, if you run the migrations again you will notice that they follow the timestamp sequence in which they originally got created:

%  rake db:migrate
== 20160916010011 CreatePosts: migrating ===========================
-- create_table(:posts)
   -> 0.0037s
== 20160916010011 CreatePosts: migrated (0.0039s) ==================

== 20160919233111 CreateAuthors: migrating =========================
-- create_table(:authors)
   -> 0.0015s
== 20160919233111 CreateAuthors: migrated (0.0016s) ================

Ok, you got the idea about migrations, now it is time to start associating these two models.

The first thing to do is to create another migration to connect them:

%  rails generate migration add_author_id_to_posts
Running via Spring preloader in process 12220
      invoke  active_record
      create    db/migrate/20160919233814_add_author_id_to_posts.rb

Of course you can choose another name for the migration (add_author_id_to_posts).

The content should be like:

class AddAuthorIdToPosts < ActiveRecord::Migration[5.0]
  def change
    add_column :posts, :author_id, :integer, index: true
    add_foreign_key :posts, :authors
  end
end

Running the migration:

%  rake db:migrate
== 20160919233814 AddAuthorIdToPosts: migrating ====================
-- add_column(:posts, :author_id, :integer, {:index=>true})
   -> 0.0153s
-- add_foreign_key(:posts, :authors)
   -> 0.0001s
== 20160919233814 AddAuthorIdToPosts: migrated (0.0157s) ===========

Ok, we have the migration, now add the relation to the model:

In app/models/post.rb:

class Post < ApplicationRecord
  validates :title, presence: true

  belongs_to :author, required: false
end

In app/models/author.rb:

class Author < ApplicationRecord
  has_many :posts, dependent: :restrict
end

In console:

%  rails c
Running via Spring preloader in process 24090
Loading development environment (Rails 5.0.0.1)
>> Author.create(name: 'John Doe')
   (0.2ms)  begin transaction
  SQL (0.7ms)  INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "John Doe"], ["created_at", 2016-09-19 23:53:49 UTC], ["updated_at", 2016-09-19 23:53:49 UTC]]
   (158.4ms)  commit transaction
=> #<Author id: 1, name: "John Doe", created_at: "2016-09-19 23:53:49", updated_at: "2016-09-19 23:53:49">

There are a lots of ways to use console to add a relation between two models, but I will use the simplest one:

%  rails c
Running via Spring preloader in process 30780
Loading development environment (Rails 5.0.0.1)
>> post = Post.first
  Post Load (0.3ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Post id: 1, title: "Testing", body: "The body here", published_at: "2015-12-31 04:02:00", created_at: "2016-09-19 23:53:28", updated_at: "2016-09-19 23:53:28", author_id: nil>
>> post.author = Author.find(1)
  Author Load (0.3ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Author id: 1, name: "John Doe", created_at: "2016-09-19 23:53:49", updated_at: "2016-09-19 23:53:49">
>> post.save
   (0.2ms)  begin transaction
  SQL (1.8ms)  UPDATE "posts" SET "updated_at" = ?, "author_id" = ? WHERE "posts"."id" = ?  [["updated_at", 2016-09-19 23:56:40 UTC], ["author_id", 1], ["id", 1]]
   (224.5ms)  commit transaction
=> true
>> Post.find(1).author.name
  Post Load (0.6ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Author Load (0.2ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "John Doe"

To get more information

Whenever I have questions I go to the Ruby on Rails Guides. These two help me out a lot:

Well, this post got bigger than I expected, but I’m very excited to show you a bunch of other features you may like. Let me know in the comments below all the questions you have ;).

We are hiring new talents. Do you want to work with us? become@codeminer42.com