Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist attributes before save #2

Merged
merged 1 commit into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions lib/vault/encrypted_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ def vault_attribute(attribute, options = {})
self
end

# Encrypt Vault attribures before saving them
def vault_persist_before_save!
skip_callback :save, :after, :__vault_persist_attributes!
before_save :__vault_encrypt_attributes!
end

# The list of Vault attributes.
#
# @return [Hash]
Expand Down Expand Up @@ -219,13 +225,7 @@ def __vault_load_attribute!(attribute, options)
# on this model.
# @return [true]
def __vault_persist_attributes!
changes = {}

self.class.__vault_attributes.each do |attribute, options|
if c = self.__vault_persist_attribute!(attribute, options)
changes.merge!(c)
end
end
changes = __vault_encrypt_attributes!

# If there are any changes to the model, update them all at once,
# skipping any callbacks and validation. This is okay, because we are
Expand All @@ -234,12 +234,24 @@ def __vault_persist_attributes!
self.update_columns(changes)
end

return true
true
end

def __vault_encrypt_attributes!
changes = {}

self.class.__vault_attributes.each do |attribute, options|
if c = self.__vault_encrypt_attribute!(attribute, options)
changes.merge!(c)
end
end

changes
end

# Encrypt a single attribute using Vault and persist back onto the
# encrypted attribute value.
def __vault_persist_attribute!(attribute, options)
def __vault_encrypt_attribute!(attribute, options)
key = options[:key]
path = options[:path]
serializer = options[:serializer]
Expand Down
53 changes: 53 additions & 0 deletions spec/unit/encrypted_model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,57 @@
expect(klass.instance_methods).to include(:foo_was)
end
end

describe '#vault_persist_before_save!' do
let(:after_save_dummy_class) do
Class.new(ActiveRecord::Base) do
include Vault::EncryptedModel
end
end

let(:before_save_dummy_class) do
Class.new(ActiveRecord::Base) do
include Vault::EncryptedModel
vault_persist_before_save!
end
end

context "when not used" do
it "the model has an after_save callback" do
save_callbacks = after_save_dummy_class._save_callbacks.select do |cb|
cb.filter == :__vault_persist_attributes!
end

expect(save_callbacks.length).to eq 1
persist_callback = save_callbacks.first

expect(persist_callback).to be_a ActiveSupport::Callbacks::Callback

expect(persist_callback.kind).to eq :after
end
end

context "when used" do
it "the model does not have a after_save callback" do
save_callbacks = before_save_dummy_class._save_callbacks.select do |cb|
cb.filter == :__vault_persist_attributes!
end

expect(save_callbacks.length).to eq 0
end

it "the model has a before_save callback" do
finalwharf marked this conversation as resolved.
Show resolved Hide resolved
save_callbacks = before_save_dummy_class._save_callbacks.select do |cb|
cb.filter == :__vault_encrypt_attributes!
end

expect(save_callbacks.length).to eq 1
persist_callback = save_callbacks.first

expect(persist_callback).to be_a ActiveSupport::Callbacks::Callback

expect(persist_callback.kind).to eq :before
end
end
end
end