Skip to content

Commit 65691d2

Browse files
committed
Improved attributes, attribute_names, and has_attribute? when ciphertext attribute not loaded - closes #186
1 parent 3fc1934 commit 65691d2

File tree

3 files changed

+39
-8
lines changed

3 files changed

+39
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## 2.0.0 (unreleased)
22

3+
- Improved `attributes`, `attribute_names`, and `has_attribute?` when ciphertext attribute not loaded
34
- Dropped support for Active Record < 7 and Ruby < 3.1
45
- Dropped support for Mongoid < 8
56

lib/lockbox/model.rb

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,40 @@ def attributes
148148
end
149149
end
150150
end
151-
super
151+
152+
# remove attributes that do not have a ciphertext attribute
153+
attributes = super
154+
self.class.lockbox_attributes.each do |k, lockbox_attribute|
155+
if !attributes.include?(lockbox_attribute[:encrypted_attribute].to_s)
156+
attributes.delete(k.to_s)
157+
attributes.delete(lockbox_attribute[:attribute])
158+
end
159+
end
160+
attributes
161+
end
162+
163+
# remove attribute names that do not have a ciphertext attribute
164+
def attribute_names
165+
# hash preserves key order
166+
names_set = super.to_h { |v| [v, true] }
167+
self.class.lockbox_attributes.each do |k, lockbox_attribute|
168+
if !names_set.include?(lockbox_attribute[:encrypted_attribute].to_s)
169+
names_set.delete(k.to_s)
170+
names_set.delete(lockbox_attribute[:attribute])
171+
end
172+
end
173+
names_set.keys
174+
end
175+
176+
# check the ciphertext attribute for encrypted attributes
177+
def has_attribute?(attr_name)
178+
attr_name = attr_name.to_s
179+
_, lockbox_attribute = self.class.lockbox_attributes.find { |_, la| la[:attribute] == attr_name }
180+
if lockbox_attribute
181+
super(lockbox_attribute[:encrypted_attribute])
182+
else
183+
super
184+
end
152185
end
153186

154187
# needed for in-place modifications

test/model_test.rb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,10 @@ def test_attributes_not_loaded
225225
assert !user.has_attribute?("name")
226226
assert !user.has_attribute?(:name)
227227

228-
# TODO try to make virtual attribute behavior consistent
229-
# this may be difficult, as virtual attributes are set to self.class._default_attributes
230-
# which gets merged with query attributes in initialize method of active_record/core.rb
231-
# assert_equal ["id"], user.attributes.keys
232-
# assert_equal ["id"], user.attribute_names
233-
# assert !user.has_attribute?("email")
234-
# assert !user.has_attribute?(:email)
228+
assert_equal ["id"], user.attributes.keys
229+
assert_equal ["id"], user.attribute_names
230+
assert !user.has_attribute?("email")
231+
assert !user.has_attribute?(:email)
235232

236233
user = User.select("id AS email_ciphertext").last
237234
assert_raises(Lockbox::DecryptionError) do

0 commit comments

Comments
 (0)