I have a simple acts_as style module, that is included in ActiveRecord::Base. The purpose of this module is to:
-
add an has_one association to an ActiveRecord model
-
add a missing method to instances, that will direct any missing methods to the associated instance.
Here is the example module:
module TestModule
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
def test_me_out
has_one :text_page
send(:include, InstanceMethods)
end
end
module InstanceMethods
def method_missing(method, *args, &block)
Rails.logger.debug "#{method}"
#text_page.send(method, *args, &block)
text_page
end
end
end
And the way I might use it in an AR model…
Class Page < ActiveRecord::Base
test_me_out
end
The problem is, if the *method_missing* method in the module is run, it immediately causes a “stack level too deep” error inside the method_missing….
app/lib/test_module.rb:24:in `method_missing'
app/lib/test_module.rb:24:in `method_missing'
app/lib/test_module.rb:24:in `method_missing'
app/lib/test_module.rb:24:in `method_missing'
app/lib/test_module.rb:24:in `method_missing'
...
The method that is missing is ‘id’ ?!? You’ll notice that I’ve commented out the example line of code that would send the missing method to the associated class – text_page.send(method, *args, &block) – since just calling the association – text_page – is enough to trigger the stack level too deep error.
Can anyone spot the error?
PS. Of course this is a boiled down example of the actual module and use case, however this illustrates the error, and fails wonderfully.
SOLUTION
Big thanks the Alex for the save. The ActiveRecord Id is generated dynamically using the method missing block. The following code works as it let the :id method missing to pass down into super:
def method_missing(method, *args, &block)
if method != :id && text_page.respond_to?(method)
text_page.send(method, *args, &block)
else
super
end
end
Erik – If I remember correctly, AR uses method_missing to define attributes accessors and the like on the class, e.g. they are not hard coded. They are stored in instance variables, but the .id and .id= methods are defined on-the-fly. As a result, I’d recommend defining a way to match missing methods that you want referred to the associated interface.