Help with method_missing in ActiveRecord

I am serializing a data object (FooData) into an ActiveRecord column
(Foo).

I’d like to be able to do delegate methods to the data class if the Foo
class doesn’t have that attribute. So instead of:

f = Foo.new
f.data.item1

I’d like to do:

f = Foo.new
f.item1

I was hoping that I could add a method_missing method to my Foo class
and
call methods in the FooData class but I’m not sure how to go about doing
that. In my example below, I get Stack Level too deep errors.

class Foo < ActiveRecord::Base
serialize :data, FooData

def after_initialize
self.data = eval("#{self.class}Data.new") unless self.data
end

def method_missing(method_name, *args)
self.data.send “#{method_name}(#{args})”
super
end
end

class FooData
attr_accessor item1, item2
end

Hi~

On Aug 5, 2006, at 9:34 PM, Hammed M. wrote:

f = Foo.new
f.item1

I was hoping that I could add a method_missing method to my Foo
class and call methods in the FooData class but I’m not sure how to
go about doing that. In my example below, I get Stack Level too
deep errors.

class Foo < ActiveRecord::Base
serialize :data, FooData

def after_initialize
self.data = eval("#{self.class}Data.new") unless self.data
end

def method_missing(method_name, *args, &blk)
if self.data.respond_to? method_name
self.data.send(method_name, args, &blk)
else
super
end
end

class FooData
attr_accessor item1, item2
end

The reason you version is overflowing the stack is because you call

super even if your method_missing works. ActiveRecord uses
method_missing to get columns so you always want to call super in
your method_missing def’s, but only if you don’t do something with
the method. So here you check if your FooData.respond_to? whatever
method invoked method_missing. And then if FooData doesn;'t respond
to that method we call super instead to let the next method_missing
pick up the method if it wants to.

Cheers-
-Ezra

Hi Ezra,

The reason you version is overflowing the stack is because you call
super even if your method_missing works.

Excellent! Thanks Ezra.

I had to add another condition to method_missing because self.data
results
in another method_missing call which calls self.data which…

def method_missing(method_name, *args, &blk)
if !method_name.eql?(:data) and self.data.respond_to? method_name
self.data.send(method_name, *args, &blk)
else
super
end
end

This is really cool - I can now pretend the methods in the data class
are
part of the ActiveRecord class. Thanks again.

Hammed