blotto
blotto

Reputation: 3407

Using ActiveRecord:Relation for specific classes, not all relations across ActiveRecord

I'm building a gem in which part of its purpose is to extend associations on a target Class. Although I can easily extend all associations by using something like :

 ActiveRecord::Relation.send(:include, MyGem::ActiveRecord::RelationMethods)

This is too broad, and for a Rails App that may use this Gem, I don't want to extend associations for all Classes.

For better granularity, I want to provide the equivalent of :

 class User < ActiveRecord::Base

    has_many :messages, :extend => MyGem::ActiveRecord::RelationMethods
    has_many :comments, :extend => MyGem::ActiveRecord::RelationMethods

 end

By using

class User < ActiveRecord::Base

    acts_as_my_fancy_gem

    has_many :messages
    has_many :comments

 end

The problem I have is trying to conditionally extend associations within the Gem, when acts_as_my_fancy_gem is added to a class. This is the bare bones of it.

module MyGem

   extend ActiveSupport::Concern

   def self.included(base)
     base.extend ClassMethods
   end  

  module ClassMethods

    def acts_as_my_fancy_gem
      include MyGem::InstanceMethods
    end

  end

  module InstanceMethods

   ...

  end
 end

I've looked into reflections, but at this point can find a clear path, and have simply taking stabs in the dark to experiment.

UPDATE:

Currently, I can achieve this with each association by providing a class method like

class User < ActiveRecord::Base

    has_many :messages
    has_many :comments

    fancy_extend :messages

 end

module MyGem

   extend ActiveSupport::Concern

   def self.included(base)
     base.extend ClassMethods
   end  

  module ClassMethods

    def acts_as_my_fancy_gem
      include MyGem::InstanceMethods
    end

    def fancy_extend *associations
       class_eval do
            associations.each do |association|
                reflections[association].options[:extend] = MyGem::ActiveRecord::RelationMethods
            end 
       end
    end


  end

  module InstanceMethods

   ...

  end
 end

Adding this approach into the act_as_my_fancy method (which is where I would like to have it) gives me :

 # NoMethodError: undefined method `options' for nil:NilClass

Upvotes: 2

Views: 471

Answers (1)

phoet
phoet

Reputation: 18845

Is this rail4? I did not find the :extend option documented. It looks like rails 4 uses blocks to do that nowadays.

It could be as simple as this:

module Fancy
  def has_many(name, scope = nil, options = {})
    super(name, scope, options) do
      def doit
        "i did"
      end
    end
  end
end

# in your model
extend Fancy

YourModel.your_relation.doit # => 'i did'

Upvotes: 1

Related Questions