Thursday, 9 January 2014

Why we use ActiveSupport::Concern

The Concern provides a mechanism for composing modules.Concerns are pieces of code that allow you to better organize the code that you write. This feature has actually been around for a long time prior to Rails 4, Rails 4 merely creates the folders for you and sets up the environment.

Included
==================================================
Module defines the callback included which is called when a module is included into another class or module.  For example see the following code:
==================================================

module Named
  def self.included(base)
    base.validates_presence_of :first_name, :last_name
  end

  def full_name
    "#{first_name} #{last_name}"
  end
end

..........................
class Person
  include Named
end



When Person includes Named, the included method is called on Named with a reference to Person. Now, what if you want a module that builds upon Named?
=================================================

module Mailable
  include Named

  def self.included(base)
    email_regexp = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/
    base.validates_format_of :email, with: email_regexp
  end

  def send_greeting
    mail = WelcomeMailer.greet(email, first_name, last_name)
    mail.deliver
  end
end

.................................................................................................................................
if we do
require 'mailable'

then it will gives
# => NoMethodError: undefined method `validates_presence_of' for Mailable:Module

This will fail when Named is included into Mailable. The Name.included callback will be executed with Mailable as the base, but Mailable doesn't define validates_presence_of:

==================================================

We really want these modules to wait until they are included in your model before the included callback is invoked. Concern works around this issue for us:

module Named
  extend ActiveSupport::Concern

  included do
    base.validates_presence_of :first_name, :last_name
  end 
end

module Mailable
  extend ActiveSupport::Concern
  include Named

  included do
    email_regexp = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/
    base.validates_format_of :email, with: email_regexp
  end
end

First a module extends Concern, and then instead of defining def self.included it calls included with a block. Concern delays calling these blocks until your module is included in something that is not a Concern.

No comments:

Post a Comment