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
-~----------~----~----~----~------~----~------~--~---

Reply via email to