Search code examples
ruby-on-railsextend

What are the Rails object 'extend' supported paths?


This has been frustrating me for 1/2 a day.

I'm trying to extend a Model of mine from a module .rb file located in a non-typical location. In my Model I try extending to a Module based on an Attribute in the Model. The Models are passed to a View, and I want the View to call the same Module method ("content") in all cases regardless of the Model's path Attribute.

 Test < ActiveRecord::Base
   ...
   after_initialization do |test|
     if !self.path.nil?
       if File.exists?('app/views/' + self.path + '/_extend.rb')
         extend 'app/views/' + self.path + '/_extend'
       end
     end
   end
   ...
 end

Just trying to dynamically add a class method from a different file. I want to try and keep things organized, which is why I want to stuff all my Module methods into the Model with a giant switch case.

Any suggestions? Thanks.


Solution

  • ruby's extend method does not work with paths. You need to supply the module you want to extend. So you should not store a path but rather some kind of type that you can later use to get a reference to the module you want to extend. A little example:

    module GuestBehavior
      def has_access?
        false
      end
    end
    
    module AdminBehavior
      def has_access?
        true
      end
    end
    
    class User < ActiveRecord::Base
      after_initialize :extend_behavior
    
      def extend_behavior
        return if kind.blank?
        behavior_module = "#{kind.capitalize}Behavior".constantize
        extend behavior_module
      end
    end
    
    admin = User.new(:kind => 'admin')
    guest = User.new(:kind => 'guest')
    
    admin.has_access? # => true
    guest.has_access? # => false
    

    This is more a though experiment than code I would actually write. It should give you an idea how to achieve your goal.

    EDIT: If you want to put the modules in different places you can easily get it working. Assuming your using rails, there is the autoloader. When you access an undefined constant the autoloader kicks in and tries to load the file, which defines that constat. The above example could look something like:

    app/models/guest_behavior.rb
    app/models/admin_behavior.rb
    

    You don't need to put any require statements in the code. Rails will automatically load the files when you access GuestBehavior or AdminBehavior. (thats what the constantize call does)