This took me a bit to figure out. Sequel has a slightly different
model than ActiveRecord does, and here's a nice introduction to it.
Both roda and sequel are very plugin heavy, which is sort of
refreshing.
1
2
| bundle add sequel sqlite3 dotenv
mkdir -p db/migrations
|
.env
:
1
| DATABASE_URL=sqlite://./db/development.db
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # db/migrations/001_accounts.rb
puts "Loading up migration"
Sequel.migration do
change do
create_table(:accounts) do
primary_key :id
String :email, null: false
Boolean :confirmed, default: false
String :name
String :login_hash
DateTime :hash_valid_until, null: true
DateTime :created_at, null: false
DateTime :updated_at, null: false
end
end
end
|
db.rb
:
1
2
3
4
5
6
7
8
| require 'dotenv/load'
require 'sequel'
throw "DATABASE_URL is unset" if !ENV['DATABASE_URL'] || ENV['DATABASE_URL'] == ""
DB = Sequel.connect( ENV['DATABASE_URL'] )
Sequel::Model.plugin :timestamps, update_on_create: true
|
Rakefile
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| require 'dotenv/load'
namespace :db do
desc "Migration the database"
task :migrate do
puts "Calling db:migrate"
require_relative 'db.rb'
version = nil
Sequel.extension(:migration)
# Perform migrations based on migration files in a specified directory.
Sequel::Migrator.apply(DB, 'db/migrations')
# Dump database schema after migration.
#Rake::Task['db:dump'].invoke
end
end
|
1
| dotenvx run -- rake db:migrate
|
[dotenvx@1.6.4] injecting env (1) from .env
Calling db:migrate
Create the model
models/account.rb
:
1
2
3
4
5
6
7
8
9
10
11
| # frozen_string_literal: true
require_relative '../db'
require 'securerandom'
class Account < Sequel::Model
def generate_login_hash
self.login_hash = SecureRandom.hex(16)
self.hash_valid_until = Time.now + 3600 # 1 hour in seconds
save
end
end
|
Building out account route
We are going to dynamically load all of the routes
in the folder so we
don't need to mess around with individually adding them. It's a nice
pattern.
Update app.rb
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| require 'roda'
class App < Roda
require_relative 'mailer.rb' # This comes later
plugin :static, ["/images", "/css", "/js"]
plugin :render
plugin :hash_branches
route do |r|
r.root do
view( :homepage )
end
Dir["routes/**/*.rb"].each do |route_file|
require_relative route_file
end
r.hash_branches
end
end
|
routes/account.rb
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| require_relative '../models/account.rb'
class App
hash_branch "account" do |r|
r.is Integer do |id|
#account = Account
"account #{id}"
end
r.on 'hash' do |hash|
r.get String do |hash|
account = Account.where( login_hash: hash ).first
if account
"Hello #{account.email}"
else
"Not found"
end
end
end
r.is do
p r.params
r.get do
"Post to create an account"
end
r.post do
account = Account.new( name: r.params["name"], email: r.params["email"] )
account.generate_login_hash
if account.save
"Hash is #{account.login_hash}"
else
puts "Missing something"
end
end
end
end
end
|
Debug
1
| curl http://localhost:9292/account
|
Post to create an account
Creating a new account:
1
2
3
4
| curl -X POST \
-F name=Will \
-F email=wschenk@gmail.com \
http://localhost:9292/account
|
Hash is 174b8bcc0d58ca52b0b2b2b36f326397
Calling it without a hash
1
| curl http://localhost:9292/account/hash
|
Calling it with the hash (the idea is that the account is verified)
1
| curl http://localhost:9292/account/hash/174b8bcc0d58ca52b0b2b2b36f326397
|
Hello wschenk@gmail.com