Como se pueden haber visto durante muchas de mis retros semanales, estuve trabajando en la migración de la tienda online de Bichomanía, de una plataforma desarrollada a medida había que pasar a una basada en Spree.
Pues bien, una de las cosas que había que traer eran los datos de clientes ya existentes y que no tuvieran que crearse un nuevo usuario. Vamos, que se mantuviera su contraseña, por lo que había que mantener el mismo algoritmo de encriptación.
Como puede ser de suponer, Spree utiliza por debajo la gema de devise para estas cuestiones. De modo que suponía que alguna forma habría de adaptarlo, y así fue, había documentación de ello.
Así que creé mi propio encryptor, de este estilo:
#config/initializers/custom_encryptor.rb
require 'digest'
module Devise
module Encryptable
module Encryptors
class CustomEncryptor < Base
def self.digest(password, stretches, salt, pepper)
Digest::SHA256.hexdigest password
end
end
end
end
end
Vale, una vez hecho esto me encontré con que tenía que extender la clase Spree::User, ya que no tengo un modelo usuario en mi aplicación como ponía en la documentación de devise. En la documentación de spree explican cómo utilizar un modelo usuario propio, pero vi que era un escenario en el que podía ser más limpio hacer uso de las posibilidades de metaprogramación que nos ofrece ruby.
De modo que lo que haríamos en un modelo propio, lo añadimos vía el uso de class_eval. Y quedaría algo así:
#app/models/user_decorator.rb
Spree::User.class_eval do
#le decimos que use nuestro encryptor
devise :encryptable, :encryptor => :custom_encryptor
#sobreescribimos el método de validación del password
def valid_password?(password)
Devise.secure_compare(
Devise::Encryptable::Encryptors::CustomEncryptor.digest(password, nil, nil, nil),
self.encrypted_password
)
end
#como no hacemos uso de salt para encriptar el password, machacamos el getter y setter
def password_salt
'no salt'
end
def password_salt=(new_salt)
end
end
Profit.