lib/lockbox/model.rb in lockbox-0.2.3 vs lib/lockbox/model.rb in lockbox-0.2.4

- old
+ new

@@ -105,11 +105,11 @@ if @lockbox_attributes.size == 1 def serializable_hash(options = nil) options = options.try(:dup) || {} options[:except] = Array(options[:except]) - options[:except] += self.class.lockbox_attributes.values.reject { |v| v[:attached] }.flat_map { |v| [v[:attribute], v[:encrypted_attribute]] } + options[:except] += self.class.lockbox_attributes.values.flat_map { |v| [v[:attribute], v[:encrypted_attribute]] } super(options) end # use same approach as devise def inspect @@ -125,22 +125,63 @@ # and then again here before_save do self.class.lockbox_attributes.each do |_, lockbox_attribute| attribute = lockbox_attribute[:attribute] - if changes.include?(attribute) && self.class.attribute_types[attribute].is_a?(ActiveRecord::Type::Serialized) - send("#{attribute}=", send(attribute)) + if changes.include?(attribute) + type = (self.class.try(:attribute_types) || {})[attribute] + if type && type.is_a?(ActiveRecord::Type::Serialized) + send("#{attribute}=", send(attribute)) + end end end end + + if defined?(Mongoid::Document) && included_modules.include?(Mongoid::Document) + def reload + self.class.lockbox_attributes.each do |_, v| + instance_variable_set("@#{v[:attribute]}", nil) + end + super + end + end end serialize name, JSON if options[:type] == :json serialize name, Hash if options[:type] == :hash - attribute name, attribute_type + if respond_to?(:attribute) + attribute name, attribute_type + else + m = Module.new do + define_method("#{name}=") do |val| + prev_val = instance_variable_get("@#{name}") + unless val == prev_val + # custom attribute_will_change! method + unless changed_attributes.key?(name.to_s) + changed_attributes[name.to_s] = prev_val.__deep_copy__ + end + end + + instance_variable_set("@#{name}", val) + end + + define_method(name) do + instance_variable_get("@#{name}") + end + end + + include m + + alias_method "#{name}_changed?", "#{encrypted_attribute}_changed?" + + define_method "#{name}_was" do + attribute_was(name.to_s) + end + end + define_method("#{name}=") do |message| original_message = message unless message.nil? case options[:type] @@ -172,12 +213,12 @@ message = [message].pack("G") unless message.nil? when :string, :binary # do nothing # encrypt will convert to binary else - type = self.class.attribute_types[name.to_s] - if type.is_a?(ActiveRecord::Type::Serialized) + type = (self.class.try(:attribute_types) || {})[name.to_s] + if type && type.is_a?(ActiveRecord::Type::Serialized) message = type.serialize(message) end end end @@ -193,10 +234,11 @@ if message.nil? || (message == "" && !options[:padding]) message else self.class.send(class_method_name, message, context: self) end + send("#{encrypted_attribute}=", ciphertext) super(original_message) end @@ -208,11 +250,12 @@ message = if ciphertext.nil? || (ciphertext == "" && !options[:padding]) ciphertext else ciphertext = Base64.decode64(ciphertext) if encode - Lockbox::Utils.build_box(self, options, self.class.table_name, encrypted_attribute).decrypt(ciphertext) + table = self.class.respond_to?(:table_name) ? self.class.table_name : self.class.collection_name.to_s + Lockbox::Utils.build_box(self, options, table, encrypted_attribute).decrypt(ciphertext) end unless message.nil? case options[:type] when :boolean @@ -231,36 +274,39 @@ message.force_encoding(Encoding::UTF_8) when :binary # do nothing # decrypt returns binary string else - type = self.class.attribute_types[name.to_s] - if type.is_a?(ActiveRecord::Type::Serialized) + type = (self.class.try(:attribute_types) || {})[name.to_s] + if type && type.is_a?(ActiveRecord::Type::Serialized) message = type.deserialize(message) else # default to string if not serialized message.force_encoding(Encoding::UTF_8) end end end # set previous attribute on first decrypt - @attributes[name.to_s].instance_variable_set("@value_before_type_cast", message) + @attributes[name.to_s].instance_variable_set("@value_before_type_cast", message) if @attributes[name.to_s] # cache if respond_to?(:_write_attribute, true) _write_attribute(name, message) - else + elsif respond_to?(:raw_write_attribute) raw_write_attribute(name, message) + else + instance_variable_set("@#{name}", message) end end message end # for fixtures define_singleton_method class_method_name do |message, **opts| - ciphertext = Lockbox::Utils.build_box(opts[:context], options, table_name, encrypted_attribute).encrypt(message) + table = respond_to?(:table_name) ? table_name : collection_name.to_s + ciphertext = Lockbox::Utils.build_box(opts[:context], options, table, encrypted_attribute).encrypt(message) ciphertext = Base64.strict_encode64(ciphertext) if encode ciphertext end end end