Concerning Rails 3 Internals

Carlos MuñizNov 30, 2011

As you may know, when we want to enhance the functionality of a class, we usually 'include' or 'extend' it through modules which include new methods or override existing ones.

We use 'include' to add Instance Methods and 'extend' for Class Methods.

With this in mind, we usually see things like:

#lib/posts_lib.rb

module PostsLib
  module ClassMethods
    def find_by_author(author)
      #...
    end
  end

  module InstanceMethods
    def post_tags()
      #...
    end
  end

  def self.included base
    base.send :include, InstanceMethods
    base.send :extend, ClassMethods
  end
end

class Post < ActiveRecord::Base
  include PostsLib
end

Looking at the code, we notice that we're overwriting the 'self.included()' method, which is a especial callback that is executed when the module is included on another class ('include PostsLib' < Right Here).

Note, we need to use base.send :extend instead because extend is a private method.

Just to clarify, this code will let us do things like:

@post.post_tags              #instance method
Post.find_by_author 'Mumo'   #class method

ActiveSupport::Concern gets rid of the self.included override altogether:

#lib/posts_lib.rb
module PostsLib
  extend ActiveSupport::Concern
  module ClassMethods
    def find_by_author(autho)
      #...
    end
  end

  module InstanceMethods
    def post_tags()
      #...
    end
  end
end

With this, we obtain clearer code and, for example, sometimes you want to add different code to self.included() such as logging:

def self.included base
  logger.warn('Something to log here')
end

Well, that's all, I'm still testing and learning, but i hope this will be useful to you in some way. ^^

Info source: Better Ruby Idioms ActiveSupport Concern Google

blog comments powered byDisqus