Search code examples
ruby-on-railsmodulemixins

Rails: callbacks from module


I try to do this:

app/models/my_model.rb:

class MyModel <  ActiveRecord::Base
  include MyModule
  ...
end

lib/my_module.rb:

module MyModule
  before_destroy :my_func    #!

  def my_func
    ...
  end
end

but I get an error:

undefined method `before_destroy' for MyModule:Module

How can I correct it.

Also I'm new to ruby. What type has these "attributes": before_destroy, validates, has_many? Are they variables or methods or what? Thanks


Solution

  • before_destroy, validates, etc. are not attributes or anything like that. These are method calls.

    In ruby, the body of a class is all executable code, meaning that each line of the class body is executed by the interpeter just like a method body would.

    before_destroy :my_func is a usual ruby method call. The method that gets called is before_destroy, and it receives a symbol :my_func as an argument. This method is looked up in the class (or module) in the scope of which it is called.

    So moving on to your question, I think now you should understand that when the interpreter loads your module

    module MyModule
      before_destroy :my_func    #!
    
      def my_func
        ...
      end
    end
    

    it starts executing its body and searches for the method before_destroy in this module and cannot find one. What you want to do is call this method not on the module, but rather on the class where the module is included. For that we have a common idiom using the Module#included method:

    module MyModule
      module InstanceMethods
        def my_func
          ...
        end
      end
    
      def self.included(base)
        base.send :include, InstanceMethods
        base.before_destroy :my_func
      end
    end