Josh Voigts
Josh Voigts

Reputation: 4132

Ruby Sinatra + Sequel constraint error handling

What is the right way to handle exceptions coming from the model in Sequel? Particularly the thing I'm running into is when the unique constraint is applied to the login. The exception in this case appears to be coming from SQLite itself instead of Sequel which means it's not getting handled by "errors".

This is the error I'm getting after trying to create a user with a "non-unique" login:

Sequel::DatabaseError at /user/create
SQLite3::ConstraintException: column login is not unique
file: database.rb location: close line: 97

Here is my abbreviated code:

require 'sinatra'
require 'sequel'

DB.create_table :users do
  primary_key :id
  String :login, :key => true, :length => (3..40), :required => true, :unique => true
  String :hashed_password, :required => true
  String :salt
  DateTime :created_at, :default => DateTime.now
end

class User < Sequel::Model
  # password authentication code
end

get '/user/create' do
  slim :user_create
end

post '/user/create' do
  user = User.new
  user.login = params['login']
  user.password = params['password']
  if user.save
    'User created'
  else
    tmp = []
    user.errors.each do |e|
      tmp << (e.join('<br/>'))
    end
    tmp
  end
end

Upvotes: 0

Views: 788

Answers (3)

Purkhalo Alex
Purkhalo Alex

Reputation: 3627

First - use validation plugin

# models/account.rb
Sequel::Model.plugin :validation_helpers

class Account < Sequel::Model
  def validate
    super
     validates_unique :login
  end
end

Next - handle error in app

# app.rb
... 
begin
  Account.create
rescue => e
  # do what you need
end
...

Upvotes: 0

cyrus
cyrus

Reputation: 1

Add the code below to handle sequel errors in sinatra.

The error block in sinatra will handle any errors thrown in one of your routes. You can specify the type of error in the first line in order to only handle those types of errors.

error Sequel::Error do
  e = env['sinatra.error']
  content_type :json
  status(400)
  return {
    message: e.message
  }.to_json
end

If you wanted to handle all errors, you would insert the following block of code.

error Exception do
  e = env['sinatra.error']
  content_type :json
  status(400)
  return {
    message: e.message
  }.to_json
end

You can combine many of these blocks so that you are handling different types of errors differently.

Upvotes: 0

Jeremy Evans
Jeremy Evans

Reputation: 12139

You probably want to use the validation_helpers plugin and use validates_unique :login inside the validate method.

Upvotes: 1

Related Questions