Integrating ActiveRecord with an SQLite3 database and RSpec Shoulda matchers into your Sinatra app
Jun 5, 2015
I ran into a lot of trouble getting this set up! Finally, everything fell into place.
While planning out a Sinatra app for a new project, I decided to use ActiveRecord to handle my data storage.
Adding ActiveRecord to your Sinatra app
Thankfully, there’s the very helpful sinatra-activerecord
gem. While we’re at it, we’ll add the sqlite3
gem:
``` ruby Gemfile gem ‘sinatra-activerecord’ gem ‘sqlite3’
Having done this, we can establish a database connection in our Sinatra app.
```ruby app.rb
require 'sinatra/activerecord'
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: 'db.sqlite3'
)
Great! Now we can add those lovely active-record
Rake tasks into our Rakefile
:
``` ruby Rakefile require ‘sinatra/activerecord/rake’
Make sure to require your Sinatra app to get the database connection
require ‘./app’
If we run `rake -T`, we'll now see a plethora of new rake tasks, all database-related:
``` ruby
rake db:create # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config)
rake db:create_migration # Create a migration (parameters: NAME, VERSION)
rake db:drop # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config)
rake db:fixtures:load # Load fixtures into the current environment's database
rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rake db:migrate:status # Display status of migrations
rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:cache:clear # Clear a db/schema_cache.dump file
rake db:schema:cache:dump # Create a db/schema_cache.dump file
rake db:schema:dump # Create a db/schema.rb file that is portable against any DB supported by AR
rake db:schema:load # Load a schema.rb file into the database
rake db:seed # Load the seed data from db/seeds.rb
rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)
rake db:structure:dump # Dump the database structure to db/structure.sql
rake db:structure:load # Recreate the databases from the structure.sql file
rake db:version # Retrieves the current schema version number
Creating an ActiveRecord migration and model
Great! Let’s create our migration to add a User model:
rake db:create_migration NAME=create_users_table
Just like in rails, this command will create the db/migrate
folder and inside it a migration file. Here, we can write up our migration:
```ruby create_users_table.rb class CreateUsersTable < ActiveRecord::Migration
# Run with `rake db:migrate` def up
create_table :users do |table|
table.string :username
table.string :password
end end
# Run with `rake db:rollback` def down
drop_table :users end end ```
Running rake db:migrate
will get our database and Users table up and good to go.
Now we can add our ActiveRecord model for a User:
```ruby models/user.rb class User < ActiveRecord::Base end
*This next part is vital.* You need to establish the connection to the database before requiring the model in the Sinatra app:
```ruby app.rb
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: 'db.sqlite3'
)
require_relative './models/user'
Doing otherwise requires you to re-establish the database connection for the user model.
Testing your ActiveRecord model with Shoulda matchers
I want to add some validations to my User model, namely, enforcing the presence of the username
and password
fields. We also want each user to have a unique username.
I’ll test this using RSpec
and shoulda-matchers
:
```ruby Gemfile group :test do gem ‘rspec’ gem ‘shoulda-matchers’ end
When you set up your `spec_helper` file, it's very important to require the Sinatra app before the test gems:
```ruby ./spec_helper.rb
require File.expand_path '../../app', __FILE__
require 'rspec'
require 'rack/test'
require 'sinatra'
require 'shoulda/matchers'
We’re now ready to test our User model. Don’t forget to require your spec_helper
:
```ruby ./spec/models/user_spec.rb describe User do it { is_expected.to validate_presence_of(:username) } it { is_expected.to validate_uniqueness_of(:username) } it { is_expected.to validate_presence_of(:password) } end
Running these will, of course, fail. So let's implement these validations!
```ruby ./models/user.rb
validates :username, :password, presence: true
validates_uniqueness_of :password
That about does it! We can now use rails-like models and validation tests in our Sinatra app.
I hope this is helpful. It took me forever to get it working!
Buy me a coffee @hola_soy_milk