ankane/blind_index

Not able to save Single Table inheritance

obromios opened this issue · 4 comments

I have a User model, where I have declared

    attr_encrypted :email, key: [ENV["EMAIL_ENCRYPTION_KEY"]].pack("H*")
    blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")

It has fields for email and type. If I retrieve a user where type is nil i.e. u=User.where(type: nil).first then

u.email ='plain@user.com'
u.save

works by filling out the encrypted fields and User.where(email: 'plain@user.com') works as expected.

However I also have a DormantUser type

class DormantUser < User
  def dormant?
    true
  end
end

If retrieve a DormantUser e.g. dormant = DormantUser.first and then do

dormant.email =  'dormant@user.com'
dormant.save

gives the following errror

ArgumentError: wrong number of arguments (given 2, expected 1)
/gems/blind_index-0.3.0/lib/blind_index.rb:21:in `generate_bidx'

How should I use the blind_index gem with Single Table Inheritance?

Hey @obromios, thanks for reporting 👍 This is fixed on master.

I tried out master and it does indeed work. It is a neat gem, thank you. One thing to consider is that when I first tried it for the DormantUser, I received the error:

TypeError: no implicit conversion of nil into Hash
gems/blind_index-d431befe9886/lib/blind_index/model.rb:24:in `merge'

Upon inspection of your test code, I tried putting the following in dormant_user.rb
blind_index :child, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
which worked fine. Is that the correct way to do this? Maybe it was just me, but if this is not obvious, it might be worth noting in your readme file.

I was adding this to an existing application and quite a few of my tests failed. The reasons for failure were pretty obvious, but I just document them below in case other people come across the same problems:

  • update_columns does not work to save the email address, whilst update does work. Presumably because your gem does something at validation.
  • SQL searches that use LIKE do not work anymore. I suspect there are a number of other SQL terms that do not work.
  • find_by_email does not work, presumably because there is no longer an email column. Because I used this a lot, I added the following code to the User model
def self.find_by_email(email)
    where(email: email).first
  end

Incidently I first tried
scope :find_by_email, ->(email) { where(email: email).first }

but this did not work on the empty case where it returned [] rather than nil. But maybe I just wrote the scope incorrectly?

Hey @obromios, thanks for the detailed update. I fixed the TypeError and added support for dynamic finders on master. You're correct about update_columns as it's designed to bypass callbacks. Also, only the equality operation will work when the data is hashed. Lastly, as far as I know, you can't return single records from scopes, which is why it returns an empty array instead of nil.

I tried d952840 and I no longer need to put
blind_index :child, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
in the inheriting classes. I also no longer need to add my own find_by_email, and will probably be using the other dynamic finders in the future. Thank you.