rubysinatrasequelbcrypt-ruby

Update user without hashing twice password


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

Solution

  • 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.