Beginners guide to Active Record
Tags: beginners, activerecord, ruby
Published: 2020-02-12 18:46:38



Intro
As a beginning programmer, normally when creating a domain model you code out your model like this:

```ruby
class Cat
 
  attr_accessor  :owner
  attr_reader :name

  @@all = []

  def initialize(name, owner)
    @name = name
    @owner = owner
    @@all << self
  end

  def self.all
    @@all
  end
end

```

What if I told you, you could create the same class with the following lines of code:

```ruby
class Cat < ActiveRecord::Base
    belongs_to :owner
end


class CreateCats < ActiveRecord::Migration[5.2]
    def change
      create_table :haunted_houses do |t|
        t.string :name
      end
    end
  end
```

Not only is the above code is easier to write/read, but it also will allow you to easily create associations between classes in the future.

In this article I will give a step by step guide on how to use Active Record in Ruby to build out a simple domain model and associate classes in that model. 

For this article we will use the example creating a shoe store.


Step 1 Adding the Active Record Gem



For the following example you will need the Active Record gem installed in your gemfile. sqlite3 and pry are also necessary for this lab. Here is an example of a gemfile with active record.

```ruby
source "https://rubygems.org"

gem "activerecord", "~> 6.0.0", :require => 'active_record'
gem "sinatra-activerecord"
gem "sqlite3", '~>1.4'
gem "rake"
gem "database_cleaner"
gem "pry"
gem "require_all"


```
Run bundle install to install your gems

Step 2 Connect to DB

After we add Active Record, we need to tell ActiveRecord where the database is located that it will be working with.

We do this by running ActiveRecord::Base.establish_connection. Once establish_connection is run, ActiveRecord::Base keeps it stored as a class variable at ActiveRecord::Base.connection.

```ruby

#config/environment.rb

require 'bundler'
Bundler.require

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'db/development.db')
require_all 'lib'
require_all 'app'


```
 


Step 3 Create model classes
For our shoe store example we will have 3 models: Shoe, Shoe_Store, and Brand.

First let's set up our shoe model class in our lb/models folder:

```ruby
# lb/app/models/shoe.rb

class Shoe < ActiveRecord::Base

end
```
By adding < ActiveRecord::Base to our shoe class, our class is now a gateway for talking to the shoes table in the database. 

Next we do the same for our brand and shoe store class.
```ruby
# lb/app/models/brand.rb

class Brand < ActiveRecord::Base

end
```
```ruby
# lb/app/models/shoe_store.rb

class ShoeStore < ActiveRecord::Base

end
```

Step 4 Create Our Migrations folders/files
In your project create the following folders: db/migrate. 

Inside db/migrate create the following files:
01_create_shoes.rb
02_create_brands.rb
03_create_shoe_stores.rb

Step 5 Create Tables

Open your newly created 01_create_shoes.rb file and 02_create_brands.rb file and add the following code:
```ruby
#01_create_shoes.rb
class CreateShoes < ActiveRecord::Migration[5.2]
    def change
        create_table :shoes do |t|
            t.string :name
            t.integer :size
            t.float :price
        end
    end
end

```
```ruby
#02_create_brands.rb
class CreateBrands < ActiveRecord::Migration[5.2]
    def change
        create_table :brands do |t|
            t.string name
        end
    end
end
```
With the following code we are able to create a table in the shoe class and brand class with columns representing the attributes of those classes.

Next add the following code to our 03_create_shoe_stores.rb file:

```ruby
class CreateShoeStores < ActiveRecord::Migration[5.2]
    def change
        create_table :shoe_stores do |t|
            t.integer :shoe_id
            t.integer :brand_id
            t.string :name
            t.string :location
            t.time :open_time
            t.time :close_time
        end
    end
end
```

Now in the terminal type rake db:migrate and you should get the following: 

```ruby
== 1 CreateShoes: migrating ===================================================
-- create_table(:shoes)
   -> 0.0007s
== 1 CreateShoes: migrated (0.0007s) ==========================================

== 2 CreateBrands: migrating ==================================================
-- create_table(:brands)
   -> 0.0015s
== 2 CreateBrands: migrated (0.0016s) =========================================

== 3 CreateShoeStores: migrating ==============================================
-- create_table(:shoe_stores)
   -> 0.0010s
== 3 CreateShoeStores: migrated (0.0010s) =====================================
```

Now if you take a look at your db/schema.rb page, you will see that all your tables with the proper columns have been created:

```ruby
ActiveRecord::Schema.define(version: 3) do

  create_table "brands", force: :cascade do |t|
    t.string "name"
  end

  create_table "shoes", force: :cascade do |t|
    t.string "name"
    t.integer "size"
    t.float "price"
  end

  create_table "shoe_stores", force: :cascade do |t|
    t.integer "shoe_id"
    t.integer "brand_id"
    t.string "name"
    t.string "location"
    t.time "open_time"
    t.time "close_time"
  end

end
```

Step 5 Rollback mistakes

What if you realized you want to rename a few of the tables in your CreateShoeStore file? What do you do? This is where rake:db:rollback is handy. Type in rake db:rollback in your terminal:

```ruby
== 3 CreateShoeStores: reverting ==============================================
-- drop_table(:shoe_stores)
   -> 0.0012s
== 3 CreateShoeStores: reverted (0.0040s) =====================================
```
Now you can make any changes to your CreateShoeStores tables. Lets change your open_time and close_time to opening_time and closing_time:

```ruby
class CreateShoeStores < ActiveRecord::Migration[5.2]
    def change
        create_table :shoe_stores do |t|
            t.integer :shoe_id
            t.integer :brand_id
            t.string :name
            t.string :location
            t.time :opening_time
            t.time :closing_time
        end
    end
end
```
Now type in rake db:migrate into your console and check your schema: 

```ruby
ActiveRecord::Schema.define(version: 3) do

  create_table "brands", force: :cascade do |t|
    t.string "name"
  end

  create_table "shoes", force: :cascade do |t|
    t.string "name"
    t.integer "size"
    t.float "price"
  end

  create_table "shoe_stores", force: :cascade do |t|
    t.integer "shoe_id"
    t.integer "brand_id"
    t.string "name"
    t.string "location"
    t.time "opening_time" #<--- changed
    t.time "closing_time" #<--- changed
  end

end
```
As you can see our changes have been implemented.

Before we start our next step lets rollback our created tables. Type rake db:rollback STEP=3 in your console:

```ruby
= 3 CreateShoeStores: reverting ==============================================
-- drop_table(:shoe_stores)
   -> 0.0008s
== 3 CreateShoeStores: reverted (0.0169s) =====================================

== 2 CreateBrands: reverting ==================================================
-- drop_table(:brands)
   -> 0.0005s
== 2 CreateBrands: reverted (0.0005s) =========================================

== 1 CreateShoes: reverting ===================================================
-- drop_table(:shoes)
   -> 0.0004s
== 1 CreateShoes: reverted (0.0005s) ==========================================
```
by adding the STEP = 3 we were able to rollback all three tables with one line of code.


Step 6 Create Associations between classes.
Not only does Active Record make it create and change tables, you can also create associations between classes with only a few lines of code. Add the following to your three model pages:

```ruby
class Shoe < ActiveRecord::Base
    has_many :shoe_stores
    has_many :brands, through: :shoe_stores
end
```
```ruby
class Brand < ActiveRecord::Base
    has_many :shoe_stores
    has_many :shoes, through: :shoe_stores
end
```
```ruby
class ShoeStore < ActiveRecord::Base
    belongs_to :shoe
    belongs_to :brand
end
```

By using the has_many or belongs_to keywords we are able to easily associate our classes.

Step 7 See our classes in action

Type rake console to get into pry where we can make some new instances.

Let's start by making a new shoe store
footlocker = ShoeStore.new(name:"Footlocker")

```ruby
=> #<ShoeStore:0x00007fc841f8ce90
 id: nil,
 shoe_id: nil,
 brand_id: nil,
 name: "Footlocker",
 location: nil,
 opening_time: nil,
 closing_time: nil>
```
Just like that we created a new instance of ShoeShore with the name Footlocker.

Now lets make a new shoe
Jordanxii = Shoe.new(name:"Jordanxii")

```ruby
=> #<Shoe:0x00007fc845098160 id: nil, name: "Jordanxii", size: nil, price: nil>
```
Now we have a shoe and a shoe store, lets make a association by typing the following 
footlocker.shoe = Jordanxii.

```ruby
=> #<Shoe:0x00007fc845098160 id: nil, name: "Jordanxii", size: nil, price: nil>
```

Now we can ask footlocker what shoes they have by typing
footlocker.shoe

```ruby
=> #<Shoe:0x00007fc845098160 id: nil, name: "Jordanxii", size: nil, price: nil>
```

As you can see we easily made an association using Active Record. Now just type the following to save it 

Jordanxii.save

If you get the following code below you have just saved your Shoe instance.

```ruby
D, [2020-02-12T10:33:00.787066 #27721] DEBUG -- :    (0.1ms)  begin transaction
D, [2020-02-12T10:33:00.799889 #27721] DEBUG -- :   Shoe Create (1.2ms)  INSERT INTO "shoes" ("name") VALUES (?)  [["name", "Jordanxii"]]
D, [2020-02-12T10:33:00.801589 #27721] DEBUG -- :    (1.4ms)  commit transaction
=> true
```

Conclusion 
As you can see with just a just a few lines of code you can create and build models with associations between them thanks to Active Record.