1

My model:

class User < Sequel::Model
self.raise_on_save_failure = false
plugin :validation_helpers
def validate
    super
    validates_format /@/, :email
    validates_presence [:email, :password]
    validates_unique :email
end

def before_save
    super
    self[:password] = BCrypt::Password.create(self[:password])
end

end

But when i update user, my password hash twice. I know it is because of before_save hook, but i want to keep sequel validating (validates_presence) real password, not result of bcrypt hash (cause BCrypt::Password.create('') is not empty)

So i need somehow do next:

  1. check if password changed
  2. validate real password by sequel
  3. save bcrypt hash of my password
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
korywka
  • 7,537
  • 2
  • 26
  • 48

2 Answers2

2

I think you should reconsider your work flow. If you want an invalid input to be only caught when trying to update the DB, why not go for something like this:

post '/update' do
  ...

  if params[:password] == nil || params[:password].empty?
    password = nil
  else
    password = BCrypt::Password.create(params[:password])
  end

  # I have no idea how this line should really look like in your code
  User.find(param[:id]).set(:password, password)

  ...
end

So basically, give it nil if the password field was not sent or empty.

As stated very clearly by iain in the comments:

[...] you should only be using Sequel to validate data that is or will be held by the database. The real password should be validated by the business logic layer, which is what is happening in this answer.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
To마SE
  • 573
  • 8
  • 19
  • thanks, but you `set` to DB hashed password. so Sequel Model will validate hash, not real password, like in case with hooks (`before_save`). your hint is okay, if i need only `validates_presence`, but min/max length we should validate manually too. I don't know is it possible to use Sequel validation helper in this case. – korywka Feb 10 '14 at 14:59
  • @bravedick From the list of hooks available [here](http://sequel.jeremyevans.net/rdoc/files/doc/model_hooks_rdoc.html) it looks like you'd better use `before_create` rather than `before_save`. – To마SE Feb 11 '14 at 02:42
  • 1
    @bravedick I think this is the correct answer, because you should only be using Sequel to validate data that is or will be *held by the database*. The real password should be validated by the business logic layer, which is what is happening in this answer. From [Why Validations?](http://sequel.jeremyevans.net/rdoc/files/doc/validations_rdoc.html#label-Why+Validations%3F) "Validations are primarily useful for associating error messages to display to the user with specific attributes on the model". – ian Feb 14 '14 at 00:09
0

You can check it in class method like this:

  if user.password_digest != expected_password
    user = nil
  end
Ravindra
  • 1,039
  • 2
  • 12
  • 26