ActiveRecord is popular Ruby gem (library) that acts as an Object-Relational-Mapper (ORM) 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 theid
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 anActiveRecord::Collection
which is anarray
-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 aclass
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 aclass
(i.e.Food.destroy_all
) or to destroy every member of anActiveRecord::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!
Top comments (0)