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/.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---