My client wants all user data encrypted, so I've created a before_save and after_find call back that will encrypt certain properties using Gibberish:
# user.rb
before_save UserEncryptor.new
after_find UserEncryptor.new
# user_encryptor.rb
class UserEncryptor
def initialize
@cipher = Gibberish::AES.new("password")
end
def before_save(user)
user.first_name = encrypt(user.first_name)
user.last_name = encrypt(user.last_name)
user.email = encrypt(user.email) unless not user.confirmed? or user.unconfirmed_email
end
def after_find(user)
user.first_name = decrypt(user.first_name)
user.last_name = decrypt(user.last_name)
user.email = decrypt(user.email) unless not user.confirmed? or user.unconfirmed_email
end
private
def encrypt(value)
@cipher.enc(value)
end
def decrypt(value)
@cipher.dec(value)
end
end
Well, when the user first signs up using Devise, the model looks about like it should. But then once the user confirms, if I inspect the user, the first_name and last_name properties look to have been encrypted multiple times. So I put a breakpoint in the before_save method and click the confirmation link, and I see that it's getting executed three times in a row. The result is that the encrypted value gets encrypted again, and then again, so next time we retrieve the record, and every time thereafter, we get a twice encrypted value.
Now, why the heck is this happening? It's not occurring for other non-devise models that are executing the same logic. Does Devise have the current_user cached in a few different places, and it saves the user in each location? How else could a before_save callback be called 3 times before the next before_find is executed?
And, more importantly, how can I successfully encrypt my user data when I'm using Devise? I've also had problems with attr_encrypted and devise_aes_encryptable so if I get a lot of those suggestions then I guess I have some more questions to post :-)