Search code examples
ruby-on-railsprivate-methodsattr-encrypted

Rails accessing private methods using attr_encrypted


I'm trying to get attr_encrypted to obscure some data before saving it to the database. I need to deal with the logger output later, but at the moment I just want to get the field data from a submitted form, encrypt it, and save it.

Here's my model:

class Agreement < ApplicationRecord
  attr_encrypted :test_field, key: :encryption_key

  private

  def encryption_key
      ENV['super_secret_key']
  end
end

I notice that when I comment out private everything seems to work as expected. But I obviously don't want to give public access to that info (ya know: super secret key), so I want it to be private. However, when I include private I get an error. Specifically: NoMethodError (undefined method 'bytesize' for :encryption_key:Symbol). What I've drilled down to is that attr_encrypted is throwing an error because it is not getting a key passed to it, because the private method is not being accessed properly.

In theory, in the attr_encrypted bit, I could just set key: ENV['super_secret_key'] rather than calling a method, but the goal here is to actually create a new class with corresponding database table by which I can save, store, and rotate my keys, which in turn are obfuscated by an environment variable for an extra layer of security.

So my real question is: what's going on with my private methods, and why is private frustrating things, even within the scope of the model? I think I'm doing something very basically incorrect, but I've also followed examples from others that do this, so any guidance on my error would be greatly appreciated!


Solution

  • The issue is that the attr_encrypted call is at the class level, the encryption_key method is instance level. Try doing this instead:

    class Agreement < ApplicationRecord
      attr_encrypted :test_field, key: ENV['super_secret_key']]
    end
    

    Admittedly untested, but it should work.

    Really though the private won't secure it anymore. You did this right by loading it through env from a config file. So long as it's not hardcoded in your repository, that's mainly what you need to do.