nordhagen
nordhagen

Reputation: 809

Rails ActiveRecord writes encrypted attribute but does not read it

I have a Patient model backed by a patients Postgres database table. It has an attribute national_id that is encrypted by the lockbox gem and therefore stored in the national_id_ciphertext column. This attribute is saved/updated fine and I can verify this in the database.

However when I read this record back, the national_id attribute is not included.

Rails console:

pry(main)> p = Patient.find(8)
=> #<Patient id: 8, name: "Øyvind Hansen", address: nil, address_directions: nil, zip: "0667", city: "Oslo", phone_number: "+4712345678", email: "[email protected]", created_at: "2020-09-05 19:41:55", updated_at: "2020-09-05 20:45:46", referral_id: nil>

pry(main)> p.national_id
=> "12345678912"

The schema is:

create_table "patients", force: :cascade do |t|
    t.string "name"
    t.string "address"
    t.string "zip"
    t.string "city"
    t.string "phone_number"
    t.string "email"
    t.text "national_id_ciphertext" # Saved, but not retrieved
    t.bigint "referral_id"
    t.index ["referral_id"], name: "index_patients_on_referral_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

The implementation of Lockbox encryption is very simple and straight from the basic example from the docs.

class Patient < ApplicationRecord
    encrypts :national_id
end

Any idea why the national_id accessor created by Lockbox are not included in enumerable model attributes?

Upvotes: 0

Views: 844

Answers (1)

SteveTurczyn
SteveTurczyn

Reputation: 36860

As you noted in your own test, the value is available. national_id is an available method on the object but is not a DB attribute. You can always retrieve it with dot notation e.g. my_patient.national_id but not through hash notation

my_patient.national_id
=> "12345678912"

my_patient["national_id"]
=> nil

This shouldn't normally be a problem, just use dot notation.

If the problem is transposing into json you can add methods to your json call...

my_patient.to_json(methods: [:national_id])

Or you can modify your to_json to include it always

class Patient < ActiveRecord
   
  def to_json(options={})
    super options.merge({methods: [:national_id]})
  end

end

Upvotes: 2

Related Questions