Skip to content

Commit

Permalink
Don't define unnecessary accessors with ActiveRecord Adapter.
Browse files Browse the repository at this point in the history
Without DB connection, ActiveRecord doesn't define methods for columns
and AttrEncrypted define attr_reader and attr_writer for the encrypted
columns.
As a result, AR model with attr_encrypted column return nil for the
target column if the DB connection was lost at the load time.

To suppress this behavior, don't define accessors if DB connection was
active.
Introduce attribute_instance_methods_as_symbols_available? to detect
connection failure with AcriveRecord Adapter.
  • Loading branch information
nagachika authored and saghaulor committed Feb 11, 2018
1 parent f70e4ac commit 98769e9
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 12 deletions.
23 changes: 15 additions & 8 deletions lib/attr_encrypted.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,19 @@ def attr_encrypted(*attributes)
encrypted_attribute_name = (options[:attribute] ? options[:attribute] : [options[:prefix], attribute, options[:suffix]].join).to_sym

instance_methods_as_symbols = attribute_instance_methods_as_symbols
attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")

iv_name = "#{encrypted_attribute_name}_iv".to_sym
attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
if attribute_instance_methods_as_symbols_available?
attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")

salt_name = "#{encrypted_attribute_name}_salt".to_sym
attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
iv_name = "#{encrypted_attribute_name}_iv".to_sym
attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")

salt_name = "#{encrypted_attribute_name}_salt".to_sym
attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
end

define_method(attribute) do
instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
Expand Down Expand Up @@ -448,6 +451,10 @@ def attribute_instance_methods_as_symbols
instance_methods.collect { |method| method.to_sym }
end

def attribute_instance_methods_as_symbols_available?
true
end

end


Expand Down
9 changes: 5 additions & 4 deletions lib/attr_encrypted/adapters/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,17 @@ def attribute_instance_methods_as_symbols
# methods returned to let ActiveRecord define the accessor methods
# for the db columns

# Use with_connection so the connection doesn't stay pinned to the thread.
connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false

if connected && table_exists?
if connected? && table_exists?
columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
else
super
end
end

def attribute_instance_methods_as_symbols_available?
connected? && table_exists?
end

# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
# encrypted attributes
#
Expand Down

0 comments on commit 98769e9

Please sign in to comment.