ActiveRecord (a Ruby gem): Common Methods
Tags: ruby, beginners, sql, database
Published: 2022-08-20 20:35:44

ActiveRecord is popular Ruby gem (library) that acts as an Object-Relational-Mapper ([ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping)) for Ruby.

ActiveRecord allows us to combine the object-oriented nature of Ruby with the functionality of relational databases. Using ActiveRecord we can easily define Ruby Classes and map those Classes to columns in a database. We can then instantiate--i.e. create--new instances of those Ruby Classes and map those instances to records (rows) in a database column. We can then finally interact with our newly constructed database with methods from the ActiveRecord gem inside of a Ruby/.rb file.

Before continuing please note that ActiveRecord uses strict naming conventions. This is what allows its default configuration to handle a lot of work for us.
- capitol, singular `Class` name for your model (`Food`)
- lowercase, plural table names (`foods`)

Suppose we have this table of `foods` (from a `Food` Ruby `class` `model` that inherits from `ActiveRecord::Base` if you are keeping track at home) :

# Table: foods
| id | name | tastiness |
| --- | --- | --- |
| 1 | hotdog | 8 |
| 2 | burger | 7 |
| 3 | ramen | 9 |
| 4 | rice | 10 |
| 5 | cheese | 4|

We could begin to access or manipulate this table using the `Food` class in a rake console session for example or in the model's .rb file. Here are some common methods & manipulations:

## get first record
`Food.first`
```
=> <Object Instance corresponding to id:1 name: "hotdog" tastiness: 8>
```
- returns the first record/`Object` instance in a column

## get record by id
`Food.find(3)`
```
=> <Object Instance corresponding to id:3 name: "ramen" tastiness: 9>
```
- returns the **first** record/`Object` instance with the `id` passed as an argument

## get record by attribute (first match only)
`Food.find_by(name: rice)`
```
=> <Object Instance corresponding to id:4 name: "rice" tastiness: 10>
```
- returns the **first** record/`Object` instance with an attribute that matches the `.find_by()` argument

## get all records by criteria (all matches)
`Food.where(' tastiness < 8 ')`
```
=> [<Object Instance corresponding to id:2 name: "burger" tastiness: 7>,
<Object Instance corresponding to id:5 name: "cheese" tastiness: 4>]
```
- returns all records/`Object` instances with an attribute that matches what was passed as an argument
- `.where` returns an `ActiveRecord::Collection` which is an `array`-like data structure that can be indexed or iterated through using array methods. _Even if there is only 1 match `.where` will always return the results in a collection._

## get all values in a column
`Food.pluck(:name)`
```
=> ["hotdog", "burger" , "ramen", "rice", "cheese"]
```
`Food.pluck(:tastiness)`
```
=> [8, 7 , 9, 10, 4]
```
- returns each value in a column as an element in an `array`

## create a new record/instance in a table (with persistence)
`Food.create(name: "eggs", tastiness: 5)`

| id | name | tastiness |
| --- | --- | --- |
| 1 | hotdog | 8 |
| 2 | burger | 7 |
| 3 | ramen | 9 |
| 4 | rice | 10 |
| 5 | cheese | 4 |
| 6 | eggs | 5 |
- under the hood this is working similar to using `.new` & `.save` together. `.new` will only create a new instance of a `class` in Ruby memory. It will not persist until it is written to the database using `.save`. `.create` does both of these for you.

## count number of records in a column
`Food.count(:name)`
```
=> 6
```
- counts the number of records in a column

## remove a record/instance in a table (with persistence)
`Food.find(2).destroy`

| id | name | tastiness |
| --- | --- | --- |
| 1 | hotdog | 8 |
| 3 | ramen | 9 |
| 4 | rice | 10 |
| 5 | cheese | 4 |
| 6 | eggs | 5 |
- `.destroy` should be used to destroy a single record/instance
- `.destroy_all` should be used to destroy multiple records such as every instance of a `class` (i.e. `Food.destroy_all`) or to destroy every member of an `ActiveRecord::Collection` (i.e. after a `.where` to do a targeted removal)

## update a record/instance in a table (with persistence)
`Food.find(6).update(name: "bread", tastiness: 9)`

| id | name | tastiness |
| --- | --- | --- |
| 1 | hotdog | 8 |
| 3 | ramen | 9 |
| 4 | rice | 10 |
| 5 | cheese | 4 |
| 6 | bread | 9 |
- you can update a single attribute such as only the name or only the tastiness or do both

You are now familiar with basic `ActiveRecord` ORM methods. If  you want to try experimenting with this data at home continue below:

---


## Set this up at home:

Provided you have an Ruby & ActiveRecord environment already configured and you are in that directory, you can try this yourself after creating (and migrating) this migration:

Brief configuration guidance:
`Gemfile`:
```
source "https://rubygems.org"

gem "activerecord", "~> 5.2"
gem "sinatra-activerecord"
gem "sqlite3"
gem "pry"
gem "require_all"
gem "rake"
```

`Rakefile`:
```
require_relative 'config/environment'
require 'sinatra/activerecord/rake'

desc 'starts a Pry console'
task :console do
  # Comment out the line below if you don't want to see the SQL logs in your terminal
  ActiveRecord::Base.logger = Logger.new(STDOUT)
  # Start a Pry session
  Pry.start
end
```

`config/database.yml`:
```
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

```

`config/environment.rb`:
```
require 'bundler'
Bundler.require

require_all 'app'

```

Now, on to actually creating this database:
```
# In a terminal window run:
$ bundle install
$ bundle exec rake db:create_migration NAME=create_foods
```

```
# inside of the db/migrate folder
# update your migration to have these attributes
# (the 5.2 should match whatever version of the activerecord gem
# you have installed in your gemfile)

class CreateFoods < ActiveRecord::Migration[5.2]
  def change
    create_table :foods do |t|
      t.string :name
      t.integer :tastiness
    end
  end
end

```
migrate your newly created migration:
```
# In a terminal window run:

$ bundle exec rake db:migrate
```
create this model:
```
# create a /app folder inside the root of your directory and put a /models folder inside of it.
# create a .rb file with your model name inside of /models 
# singular and lowercase i.e. /app/models/food.rb

class Food < ActiveRecord::Base
end
```


populate/seed your database with data (create instances of the Food class that will exist inside of your `foods` table```
# create a "seeds.rb" file inside of the /db directory

Food.create(name: "hotdog", tastiness: 8)
Food.create(name: "burger", tastiness: 7)
Food.create(name: "ramen", tastiness: 9)
Food.create(name: "rice", tastiness: 10)
Food.create(name: "cheese", tastiness: 4)
```

```
# In a terminal window run:

$ bundle exec rake db:seed
```

You have now:
1) Defined your table structure
2) Created your table
3) Defined what class belongs your the table
4) Filled your table with instances of your class

You can new view your database using an IDE + an extension (such as Visual Studio Code /w the SQLite extension or using a standalone database viewer app).

Feel free to try access and manipulate your table inside of a `rake console` session in your terminal or from inside your model's class definition now.

Happy rubying!