On 6/28/06, Alex Y. [email protected] wrote:
I’d have SomeAsset and AnotherAsset instances each hold a delegate Asset
object that they proxy any calls they can’t answer themselves to. I’ve
played around a little with trying to implement a full class table
inheritance scheme for AR on that basis, but never really had enough
need for it myself to polish it up.
I agree with Alex here. While inheritance was what the tables were
originally trying to emulate, composition was the resulting design
anyways. With Ruby and it’s duck typing, inheritance isn’t required
for the ability to pass a SomeAsset where an Asset is expected. Java’s
static typing would require SomeAsset to “be a” Asset, but Ruby only
needs SomeAsset to “quack like” an asset, which can be covered with
judicious use of composition and method_missing. I’d actually provide
a mixin that sets up this method_missing. Example:
class Asset < ActiveRecord::Base
# we’re leaving out the reverse relationship to the “child” classes
# – just as a parent class implementation wouldn’t really know
about
# the classes descended from it
def xyzzy
# model specific functionality
end
def hidden
# model specific functionality that's not delegatable
end
module Delegator
AssetDelegates = [ :prop1, :prop1=, :xyzzy ]
def self.included(other)
other.module_eval <<-END
# we use belongs_to rather than has_one because the foreign
key
# is in this table
belongs_to :asset
alias :__asset_delegator_old_mm :method_missing
def method_missing(method, *args, &block)
if AssetDelegates.include?(method)
self.asset.send(method, *args, &block)
else
__asset_delegator_old_mm(method, *args, &block)
end
end
END
end
end
end
class SomeAsset < ActiveRecord::Base
include Asset::Delegator
def xyzzy
# override Asset's implementation of xyzzy, feels just like
# inheritance, except that if we want to call up to the "parent"
# version, we need to use asset.xyzzy rather than super
end
end
class AnotherAsset < ActiveRecord::Base
include Asset::Delegator
# make the hidden method, which wasn't explicitly delegated,
available
# from this “subclass”
def hidden
asset.hidden
end
end
Jacob F.