Write-only fields with ActiveRecord

I made a custom ActiveModel::Type to encrypt a field before it goes to the database. The context is that multiple apps use the same database. Some write to it, some read from it. Now my side is write-only. I should never read the field, neither can I decrypt it.

How do we handle write-only fields with ActiveRecord?

  • Should I raise?
  • Should I return nil?
  • Should I return the ciphertext stored in the database?
  • Is an ActiveModel::Type not made for this? e.g. Devise doesn’t use it.
  • What do other people do?

This is my sketch. It raises:

class RsaEncryptedType < ActiveModel::Type::String
  def initialize(public_key: nil, private_key: nil)
    raise "At least public_key or private_key must be present" unless public_key.present? || private_key.present?

    @private_key = OpenSSL::PKey::RSA.new(private_key) if private_key.present?
    @public_key = OpenSSL::PKey::RSA.new(public_key) if public_key.present?
  end

  def type
    :rsa_encrypted
  end

  def serialize(value)
    return nil if value.blank?
    raise "Cannot encrypt. Public key missing." if @public_key.nil?

    ciphertext = @public_key.public_encrypt(value.to_s)
    Base64.strict_encode64(ciphertext)
  end

  def deserialize(value)
    return nil if value.blank?
    raise "Cannot decrypt. Private key missing." if @private_key.nil?

    ciphertext = Base64.decode64(value)
    @private_key.private_decrypt(ciphertext)
  end
end

I think you could add the following method to your model to make it read only:

def readonly? true end

you are right Tobias L. Maier