views:

281

answers:

1

I have a some code in an engine style plugin which includes some models. In my app I want to extend one of these models. I have managed to add both instance and class methods to the model in question by including a module from within an initializer.

However I cannot seem to add associations, callbacks etc. I get a 'method not found' error.

/libs/qwerty/core.rb

module Qwerty
  module Core
    module Extensions

      module User
        # Instance Methods Go Here 

        # Class Methods
        module ClassMethods
          has_many  :hits, :uniq => true # no method found

          before_validation_on_create :generate_code # no method found

          def something # works!
            "something"
          end
        end

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

/initializers/qwerty.rb

require 'qwerty/core/user'

User.send :include, Qwerty::Core::Extensions::User
+2  A: 

I think this should work

module Qwerty
  module Core
    module Extensions
      module User
      # Instance Methods Go Here 

        # Class Methods
        module ClassMethods
          def relate
            has_many  :hits, :uniq => true # no method found

            before_validation_on_create :generate_code # no method found
          end

          def something # works!
            "something"
          end
        end

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

The old code is wrong cause the validation and the association are called upon module loading, and this module knows nothing about ActiveRecord. That's a general aspect of Ruby, code inside class or module bodies is called directly when loaded. You don't want that. To get around that you can use the above solution.

khelll
Gotcha: When doing a 'reload!' in the console the class gets reloaded but because the module (in my case) is called from an initializer the module is not reapplied.
Kris
Further more at the moment it appears the code in the module only gets included when using the console, when the same code is called from a controller it fails. I'd like to post a code example but an answer does not seem right (this is not a forum after all)...
Kris
CONTROLLER: render :text => User.new.respond_to?('hits') and return #=> falseCONSOLE: User.new.respond_to?('hits') # => truePREEMPT: I have rebooted the server :)
Kris
Must be code reloading - I set up a fresh Rails app, the first request (after server boot) works, the class in question has the module code included, the second request fails.
Kris