lib/lockbox/model.rb in lockbox-1.0.0 vs lib/lockbox/model.rb in lockbox-1.1.0

- old
+ new

@@ -224,9 +224,55 @@ end end result end + + if ActiveRecord::VERSION::MAJOR >= 6 + def self.insert_all(attributes, **options) + super(lockbox_map_attributes(attributes), **options) + end + + def self.insert_all!(attributes, **options) + super(lockbox_map_attributes(attributes), **options) + end + + def self.upsert_all(attributes, **options) + super(lockbox_map_attributes(attributes, check_readonly: true), **options) + end + + # private + # does not try to handle :returning option for simplicity + def self.lockbox_map_attributes(records, check_readonly: false) + return records unless records.is_a?(Array) + + records.map do |attributes| + # transform keys like Active Record + attributes = attributes.transform_keys do |key| + n = key.to_s + attribute_aliases[n] || n + end + + lockbox_attributes = self.lockbox_attributes.slice(*attributes.keys.map(&:to_sym)) + lockbox_attributes.each do |key, lockbox_attribute| + attribute = key.to_s + # check read only + # users should mark both plaintext and ciphertext columns + if check_readonly && readonly_attributes.include?(attribute) && !readonly_attributes.include?(lockbox_attribute[:encrypted_attribute].to_s) + warn "[lockbox] WARNING: Mark attribute as readonly: #{lockbox_attribute[:encrypted_attribute]}" + end + + message = attributes[attribute] + attributes.delete(attribute) unless lockbox_attribute[:migrating] + encrypted_attribute = lockbox_attribute[:encrypted_attribute] + ciphertext = send("generate_#{encrypted_attribute}", message) + attributes[encrypted_attribute] = ciphertext + end + + attributes + end + end + end else def reload self.class.lockbox_attributes.each do |_, v| instance_variable_set("@#{v[:attribute]}", nil) end