Active Record
Setup and usage of ActiveRecord ORM
ActiveRecord is a database management pattern that the Ruby on Rails team codified into a Rubygem. The ActiveRecord gem has been ported to work with Sinatra through the sinatra-activerecord
gem. This gem (library) allows you to connect to a variety of database engines, create models, and run CRUD actions through those models.
IMPORTANT LINKS & RESOURCES
- Sinatra ActiveRecord dcss
- ActiveRecord Query Interface. Although this was written for Ruby on Rails, all of the same methods still apply because Sinatra-ActiveRecord is simply a port of the original ActiveRecord gem made to work with Sinatra. It works the same way in Sinatra as it does in Rails. Any differences will be documented here (there are very few)
- SQLite Browser is a Mac application that lets you open Sqlite databases (
.sqlite
and.sqlite3
files) and visually inspect your database table data.
About Relational Database Engines
Before you install the sinatra-activerecord
gem you have to decide which database engine you're going to use for your data. Unlike Node.js with it's default assumption that you'll use a non-relational, NoSQL database, Ruby applications traditionally use relational databases. Of course, the kind of database you use should be determined by the kind of data you'll be storing but for the sake of this lesson we'll be using a relational database. There are many relational database engines to choose from. The most popular are:
- MySQL - A free and open source relational database engine developed by Oracle in the 90's. It is the most popular and widely used database engine in production environments
- PostgreSQL - Another free and open source relational database engine developed by a computer science professor at UC-Berkely. In the past decade developers have started to rediscover its performance benefits and features that some other databases don't have and has begun to become a popular choice for developers whose language of choice is anything but PHP. Postgres is not as user-friendly as MySQL and so it is often difficult to introduce to new developes
- SQLite is a light and portable free, open source relational database engine. It is most often embedded into iOS applications and used in cases where performance is not critical and the amount of data stored will be small. SQLite is easy to set up - you just create a
.sqlite
file - which is why it is almost always used as a development database for web applications.
In development mode SQLite is easy to work with so we'll be using it in our applications in development mode. When we launch our apps into production (on a live, public server) we'll use MySQL as it performs better in a production environment but requires additional setup steps that SQLite doesn't.
Installation and Setup
Let's get ActiveRecord installed and configured for Sinatra
Installing it
Remember how we had to decide which database engine we want to use? Here's where this choice becomes important. Before we can use ActiveRecord we need to install a database driver gem for the database we'll be using. Since we're using SQLite in development mode, we'll need to install the SQLite3 gem in our Gemfile
's :development
group. This will allow our app, or more specifically, ActiveRecord, to speak to SQLite databases. The database driver gem acts as a translator between the database engine and your ORM.
Once we've installed the driver we can focus on the ORM. We're using sinatra-activerecord
in this case. So ActiveRecord is an ORM which translates Ruby code into SQL code that a database can understand and our database driver allows our ORM to connect to our database. The flow looks like this: Ruby Code -> ORM -> Connect to DB via Driver -> ORM turns Ruby code into SQL on the connected DB
.
Your Gemfile
should look like this:
source 'https://rubygems.org'
gem 'bundler', '~> 1.12', '>= 1.12.5'
gem 'sinatra', '~> 1.4', '>= 1.4.7', require: 'sinatra/base'
gem 'sinatra-activerecord', '~> 2.0', '>= 2.0.10', require: 'sinatra/activerecord'
group :development do
gem 'rerun', '~> 0.11.0'
gem 'sqlite3', '~> 1.3', '>= 1.3.11'
end
After editing your Gemfile
run bundle install
to install the newly added gems.
Now we're ready to start configuring ActiveRecord so it properly connects to our database.
Configuration
1 Create config files
ActiveRecord uses a configuration file to do some of its work, especially in it's Rake tasks. So the first thing we need to do is create a config folder and a database YAML file. ActiveRecord expects these to exist to work. So first we run mkdir config && touch config/database.yml
Within the database.yml
file we need a section for each environment that defines the database connection configuration for that environment. For now we only have a development environment so our database.yml
file will look like this:
development:
adapter: sqlite3
database: ../db.sqlite3
The Sinatra-ActiveRecord gem will automatically look for and read this file when it runs. The development:
key specifies the environment the configuration is for. The adapter
key specifies which database you're using (this lets it know which driver gem to use). Finally, the database
key specifies the location of the database. Since this is an SQLite database it is stored in a regular file unlike MySQL or other databases which run on ports (like mysql://username:password@localhost:3306/db_name
).
You can learm more about YAML here
2 Add database tasks to your Rakefile
Now that you have a configuration file set up you need to add the ActiveRecord Rake tasks to your Rakefile. This is as simple as requiring a library at the top of your Rakefile
and running the database connection code.
At the top of your Rakefile
add the following require statement:
require 'sinatra/activerecord/rake'
Next, just below the require statement, you need to add code that connects to your database. ActiveRecord will connect to your database based on your environment (ENV['RACK_ENV']
). By default your environment will be development
unless otherwise specified. Now, add this code to create a connection to your database:
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => 'db.sqlite3'
)
We can write this code in a way that will automatically choose the correct database configuration variabless but for now we're just hard coding the configuration. For now we're simply hard coding the SQLite3 adapter and manually specifying the database file for this SQLite database.
The require statement along with the database connection statement will make a set of new Rake rasks available to you and those tasks will take advantage of the database connection code to do their job.
At this point if you run rake -T
you will see many more Rake tasks than you've actually defined in your Rakefile. These come from the require
statement you added at the top of the Rakefile.
3 Connect your application to the database
At this point we have configured ActiveRecord and added some Rake tasks. Now we want our application to be able to take advantage of this database connection. To do this, open up your config.ru
file and add the following code just after your Bundler.require
statement:
# config.ru
require 'bundler'
Bundler.require :default, ENV['RACK_ENV'].to_sym
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => 'db.sqlite3'
)
# Require models here
# Require controllers and middleware here
# Map (mount) controllers at paths here
By adding the ActiveRecord::Base.establish_connection(...)
line to your config.ru
file you are creating a persistent database connection that your application's models can use to communicate with the database.
4 Create your database schema
Now we'll use ActiveRecord's Rake tasks to create a database migration. Migration files are used to translate the code from your language of choice into something your database can understand. Migrations are files that are written in Ruby (they can be in any language but we're using Ruby in this case) that define your database schema. Here we're going to create a migration that creates a new database table and defines its columns. *Note that ActiveRecord will automatically create a primary key column called id
for any new table you create. Migrations can be used to create, update, and destroy database tables.
Let's create a new users table:
First we'll create a migration file stub by using a Rake task then filling it out with the details we want. Run the following in your terminal:
rake db:create_migration NAME=create_users
This will create a new file in db/migrate/<today's_date_migration_name>.rb
Now open the file and you'll see the following:
class CreateUsers < ActiveRecord::Migration
def change
# Your table schema here
end
end
Inside of the change
method we're going to add some code so that the final file looks like this:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :password
end
end
end
What this is saying is: "Create a table called users with a string column called 'username' and a string column called 'password'". The primary key, id
, will always be created automatically for you so you do not need to manually define it in your migration.
5 Run migrations (set up the database)
The final step to adding tables to our database is to run the migration file(s). To do this simply run rake db:migrate
in your terminal and a new table will be added to your database. You can manually check to see if the migration worked as expected in a few ways:
- If there are no error messages then you should be fine
- Use the
sqlite
CLI to browse your database (not recommended - the MySQL CLI is the only database CLI we'll cover in class) - Use the SQLite Browser application to open the
db.sqlite3
file and then navigate to the "Browse Data" tab to view the tables and the data within those tables in your database
Models
Now we have a database connection within our app along with a ready-to-use database. All that's left is to define a model we can use to perform CRUD operations on your database.
First create a models folder in your app folder by running mkdir app/models
.
Next let's create a User model. Create a new file by running touch app/models/user.rb
and add the following code to it:
class User < ActiveRecord::Base
# You don't need to add any methods or attributes here but you can.
# ActiveRecord comes with some helpful methods for validating data
# before it gets saved to the database but for now an empty model
# class is all you need to start storing data.
end
Model Relations
We can specify relations between models in code which translate directly into the same relations that are defined in the database tables using foreign keys and primary keys:
class User < ActiveRecord::Base
has_many :todos
end
class Todo < ActiveRecord::Base
belongs_to :user
end
In the above code we use the relational methods has_many
and belongs_to
. Here our models are basically saying "A User has many todos" and "Each todo belongs to a single user".
CRUD Actions on Models
Now we can use our User model to save users to our database in 2 easy steps.
- Add a require statement right before you require your models in
config.ru
but after the DB connection code. - Now you have access to a
User
object in all of your controllers.
Example of how to save a new user to the database
Let's say you wanted to save a username and password from some URL parameters. Here's how to do it: (You should always use forms for this but we're gonig to use a simpler method for the sake of this example)
# in config.ru
#
# By now you've required all your dependencies and controllers
# and we're in the mapping section of the file
map('/users') { run UsersController }
map('/') { run HomeController }
# in app/controllers/users_controller.rb
class UsersController < ApplicationController
get '/:username/:password/?' do |username, password|
if username != '' && password != ''
user = User.create username: username, password: password
end
if user
'User was created'
else
'There was an error creating a user'
end
end
end
With the server running you can now visit http://localhost:9292/users/
Check out the ActiveRecord Query Interface docs to learn more about the methods that ActiveRecord makes available to all of your models. There are methods for Creating, Reading, Updating, and Deleting database records.
Conclusion
This is just the beginning. There is so much more that you can do with ActiveRecord in Sinatra. These notes only cover the basic installation, setup, and usage of a single model method. You can manage data in any way imaginable with the tools you just set up. Relational databses are powerful tools. Take advantage of them.