From 1bd737c12d11f71f2ec154c1bab467c2b06dd49e Mon Sep 17 00:00:00 2001 From: Tony Marklove Date: Tue, 14 Jan 2020 17:27:42 +0000 Subject: [PATCH] Define additional methods for all attributes When defining multiple attributes in a single `attr_encrypted` definition, all of the attributes should have methods such as `"#{attr}_changed?"` and `"#{attr}_was"` defined. Currently only the last attribute is popped from the array, and methods for all other attributes are not created. For example: ``` attr_encrypted :name, :email email_was # => defined email_changed? # => defined name_was # => not defined name_changed? # => not defined ``` --- lib/attr_encrypted/adapters/active_record.rb | 53 +++++++++++--------- test/active_record_test.rb | 15 +++++- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/lib/attr_encrypted/adapters/active_record.rb b/lib/attr_encrypted/adapters/active_record.rb index fca9343e..61003486 100644 --- a/lib/attr_encrypted/adapters/active_record.rb +++ b/lib/attr_encrypted/adapters/active_record.rb @@ -49,40 +49,43 @@ def attributes=(*args) protected # attr_encrypted method - def attr_encrypted(*attrs) + def attr_encrypted(*attributes) super - options = attrs.extract_options! - attr = attrs.pop - attribute attr if ::ActiveRecord::VERSION::STRING >= "5.1.0" - options.merge! encrypted_attributes[attr] - define_method("#{attr}_was") do - attribute_was(attr) - end + options = attributes.extract_options! + + attributes.each do |attr| + attribute attr if ::ActiveRecord::VERSION::STRING >= "5.1.0" + options.merge! encrypted_attributes[attr] - if ::ActiveRecord::VERSION::STRING >= "4.1" - define_method("#{attr}_changed?") do |options = {}| - attribute_changed?(attr, options) + define_method("#{attr}_was") do + attribute_was(attr) end - else - define_method("#{attr}_changed?") do - attribute_changed?(attr) + + if ::ActiveRecord::VERSION::STRING >= "4.1" + define_method("#{attr}_changed?") do |options = {}| + attribute_changed?(attr, options) + end + else + define_method("#{attr}_changed?") do + attribute_changed?(attr) + end end - end - define_method("#{attr}_change") do - attribute_change(attr) - end + define_method("#{attr}_change") do + attribute_change(attr) + end - define_method("#{attr}_with_dirtiness=") do |value| - attribute_will_change!(attr) if value != __send__(attr) - __send__("#{attr}_without_dirtiness=", value) - end + define_method("#{attr}_with_dirtiness=") do |value| + attribute_will_change!(attr) if value != __send__(attr) + __send__("#{attr}_without_dirtiness=", value) + end - alias_method "#{attr}_without_dirtiness=", "#{attr}=" - alias_method "#{attr}=", "#{attr}_with_dirtiness=" + alias_method "#{attr}_without_dirtiness=", "#{attr}=" + alias_method "#{attr}=", "#{attr}_with_dirtiness=" - alias_method "#{attr}_before_type_cast", attr + alias_method "#{attr}_before_type_cast", attr + end end def attribute_instance_methods_as_symbols diff --git a/test/active_record_test.rb b/test/active_record_test.rb index 8ec31aea..ef99401c 100644 --- a/test/active_record_test.rb +++ b/test/active_record_test.rb @@ -9,13 +9,16 @@ def create_tables self.verbose = false create_table :people do |t| t.string :encrypted_email + t.string :encrypted_name t.string :password t.string :encrypted_credentials t.binary :salt t.binary :key_iv t.string :encrypted_email_salt + t.string :encrypted_name_salt t.string :encrypted_credentials_salt t.string :encrypted_email_iv + t.string :encrypted_name_iv t.string :encrypted_credentials_iv end create_table :accounts do |t| @@ -57,7 +60,7 @@ class UploadedFile; end class Person < ActiveRecord::Base self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt - attr_encrypted :email, key: SECRET_KEY + attr_encrypted :email, :name, key: SECRET_KEY attr_encrypted :credentials, key: Proc.new { |user| Encryptor.encrypt(value: user.salt, key: SECRET_KEY, iv: user.key_iv) }, marshal: true after_initialize :initialize_salt_and_credentials @@ -337,4 +340,14 @@ def test_should_evaluate_proc_based_mode refute_equal address.encrypted_zipcode, zipcode assert_equal address.zipcode, zipcode end + + def test_additional_methods_defined_for_all_attributes + assert Person.method_defined?(:email_was) + assert Person.method_defined?(:email_changed?) + assert Person.method_defined?(:email_change) + + assert Person.method_defined?(:name_was) + assert Person.method_defined?(:name_changed?) + assert Person.method_defined?(:name_change) + end end