LoginSignup
11
9

More than 5 years have passed since last update.

attr_encryptedでハマった話

Last updated at Posted at 2014-04-22

attr_encryptedという暗号化をしてくれるgemでちょっとハマりました。

現象

abstract_user.rb
class AbstractUser < ActiveRecord::Base
  self.abstract_class = true

  attr_accessible :name, :password
  attr_encrypted :password, key: 'secretkey'
end
user.rb
class User < AbstractUser
end
irb> user = User.new(name: 'hoge', password: 'fuga')
irb> user.encrypted_password   # => 暗号化されたパスワード
irb> user.password             # => 'fuga'
irb> user[:encrypted_password] # => nil !?
irb> user.save                 # => encrypted_passwordはNULLで保存される(NOT NULL制約があるならエラー)

原因

#encrypted_password[:encrypted_password](read_attribute(:encrypted_password))の返す値が違うんだと思って定義元を調べてみたら、以下のコードを発見。

attr_encrypted.rb
131: attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
132: attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")

こういう時pryの$ methodは便利ですね。
つまり、#encrypted_password, #encrypted_password=はActiveRecordとは切り離された、プレーンなアクセサになっていました。
abstractな親クラスでattr_encryptedしていたため、AbstractUser.instance_methodsencrypted_passwordを含まず、attr_encryptedが独自のアクセサを定義してしまったようです。
attr_encryptedはActiveRecordに限らず、すべてのオブジェクトで使えるように設計されている(Objectをextendしている)ので、こういう実装になっているんでしょうね。

ActiveRecordの実装までは追っていませんが、カラム名のメソッドはおそらくmethod_missingなどで実装されていて、instance_methodsも具象クラスならカラム名のメソッドをすべて含むようにオーバーライドされているんでしょう。
アクセサが定義されたことにより、ActiveRecordの実装が無効化されてしまったという事だろうと思っています。

11
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9