I want to extend the functionality of ActiveRecord''s
`belongs_to'' macro
method so that, in addition to performing its normal tasks and creating
the default association methods, I can have it also create a couple
extra *custom* association methods. I''ll post my code of how I tried
(and failed) to do this below. Anyone know if/how this can be done?
Specifically, what I''m doing is trying to have `belongs_to''
add two more
methods to an AR class *if* the association is polymorphic
(options[:polymorphic] == true). If the association is polymorphic, I
try to add the following two custom association methods:
__CODE__
def association_string
"#{association.id}:#{association.class.base_class}"
end
def association_string=(ref)
i, t = ref.split('':'')
association = eval(t).find(i.to_i)
end
__CODE__
I try to override belongs_to by using `alias_method_chain'' so I can
call
the original implementation, followed by my own logic. The code is in a
file in my `config/initializers'' directory so it will get picked up
when
the rails env loads.
The error I get is: `alias_method'':NameError: undefined method
`belongs_to'' for class `ActiveRecord::Base''
Indeed, if I load a script/console session and do:
ActiveRecord::Base.methods.find {|m| m =~ /belongs_to/}
I get no match for `belongs_to'' (though
`has_and_belongs_to_many'' *is*
found interestingly enough).
I see that in the docs `belongs_to'' is in module
ActiveRecord::Associations::ClassMethods which, I''d assume, gets
included (or extended) into AR::Base, making the method available.
Either way, the method I need to override isn''t defined/part-of
AR::Base. Anyone know how/why/what/where or how to better accomplish the
above?
Here''s the full code listing of what I''m trying to do:
FILE: config/initializers/polymorphic_references.rb
==========CODE=========
module PolymorphicReferences
##########
#
# Extensions to ActiveRecord
#
module ActiveRecord
def self.included(base)
base.send :extend, ClassMethods
base.send :include, InstanceMethods
base.send :alias_method_chain, :belongs_to, :polymorphism
end
##########
#
# ActiveRecord::Base class methods
#
module ClassMethods
#
# Load object polymorphically
#
def polymorphic(class_or_str, record_id = nil)
i = t = nil
if class_or_str.is_a?(String) and record_id.nil?
i, t = class_or_str.split('':'') rescue [nil, nil]
raise ArgumentError, "...message..." unless
i.is_a?(String) and t.is_a?(String)
i = i.to_i rescue nil
t = eval(t) rescue nil
elsif class_or_str.is_a?(String) and
record_id.is_a?(Integer)
i = record_id
t = eval(class_or_str) rescue nil
elsif class_or_str.is_a?(Class) and
record_id.is_a?(Integer)
i = record_id
t = class_or_str
else
raise ArgumentError, "...message..."
end
raise ArgumentError, "...message..." unless i
raise ArgumentError, "...message..." unless t
raise ArgumentError, "...message..." unless i > 0 and
t.respond_to?(:descends_from_active_record?) and
t != ::ActiveRecord::Base
t.base_class.find(i)
end
#
# Hook into belongs_to to add association_string methods:
#
def belongs_to_with_polymorphism(association_id, options = {})
add_poly = options[:polymorphic]
belongs_to_without_polymorphism(association_id, options)
if add_poly
string_reader = "#{association_id}_string"
string_writer = "#{association_id}_string="
object_reader = association_id.dup
object_writer = "#{association_id}="
define_method(string_reader) do
ref = self.send(object_reader)
ref.polymorphic rescue nil
end
define_method(string_writer) do |reference|
obj = self.class.polymorphic(reference) if reference
self.send(object_writer, obj)
end
end
end
end
##########
#
# ActiveRecord::Base instance methods
#
module InstanceMethods
#
# This returns a polymorphic "reference" string.
#
def polymorphic
return nil if new_record?
"#{id}:#{self.class.base_class}"
end
end
end
end
#
##########
#
# Plug the system into rails
#
ActiveRecord::Base.send :include, PolymorphicReferences::ActiveRecord
========== END OF CODE =========
Thanks in advance for any help/responses/insights/condolences.
--
Posted via http://www.ruby-forum.com/.