Skip to content

Commit

Permalink
Fix SystemStackError when extending the reload method with Module#pre…
Browse files Browse the repository at this point in the history
…pend

For example, when using the master branch of activerecord-multi-tenant, if activerecord-multi-tenant and attr_encrypted are listed in the Gemfile in that order, calling the reload method raises a SystemStackError. This happens because activerecord-multi-tenant extends Active Record’s reload method using prepend, while attr_encrypted extends it using an alias method.

Here’s an example of how extending the same method with both prepend and alias methods in that order can result in a SystemStackError

```
class Hello
  def hello
    'hello'
  end
end

Hello.prepend(Module.new do
  def hello
    super
  end
end)

Hello.class_eval do
  alias orig_hello hello

  def hello
    "#{orig_hello} world"
  end
end

Hello.new.hello #=> SystemStackError
```

However, reversing the order works:

```
class Hello
  def hello
    'hello'
  end
end

Hello.class_eval do
  alias orig_hello hello

  def hello
    "#{orig_hello} world"
  end
end

Hello.prepend(Module.new do
  def hello
    super
  end
end)

Hello.new.hello #=> "hello world"
```

This issue can be resolved by standardizing the method extension to use prepend to avoid conflicts.
  • Loading branch information
willnet committed Sep 12, 2024
1 parent 17ac2f0 commit 6010192
Showing 1 changed file with 11 additions and 11 deletions.
22 changes: 11 additions & 11 deletions lib/attr_encrypted/adapters/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ module Adapters
module ActiveRecord
RAILS_VERSION = Gem::Version.new(::ActiveRecord::VERSION::STRING).freeze

def self.extended(base) # :nodoc:
base.class_eval do

# https://github.com/attr-encrypted/attr_encrypted/issues/68
alias_method :reload_without_attr_encrypted, :reload
def reload(*args, &block)
result = reload_without_attr_encrypted(*args, &block)
self.class.attr_encrypted_encrypted_attributes.keys.each do |attribute_name|
instance_variable_set("@#{attribute_name}", nil)
end
result
module Reload
def reload(...)
result = super
self.class.attr_encrypted_encrypted_attributes.keys.each do |attribute_name|
instance_variable_set("@#{attribute_name}", nil)
end
result
end
end

def self.extended(base) # :nodoc:
base.class_eval do
attr_encrypted_options[:encode] = true

class << self
Expand Down Expand Up @@ -148,5 +147,6 @@ def method_missing_with_attr_encrypted(method, *args, &block)
ActiveSupport.on_load(:active_record) do
extend AttrEncrypted
extend AttrEncrypted::Adapters::ActiveRecord
prepend AttrEncrypted::Adapters::ActiveRecord::Reload
end
end

0 comments on commit 6010192

Please sign in to comment.