Do you concern concerns?

Do you concern concerns?

Concerns in Ruby on Rails

By reading this tutorial you will be able to use Active Model concerns in Ruby on Rails.

Recently you may have noticed that starting from version 4 Rails creates a new folder called Concerns.

What are concerns?

Concerns are pieces of code that allow you to organize, in much better and effective way, the code that you write. This feature has actually been around for a long time prior to Rails 4, which merely creates the folders for you and sets up the environment.
In this article, we focus primarily on Rails versions starting from 4.0, but it should apply equally to 3.2.x or even 3.0.x and earlier.
So let’s say we have a model called User, this model would typically look as shown below:

class User < ActiveRecord::Base
  has_secure_password

  def self.authenticate(email, password)
    user = find_by_email(email)
    user if !user.nil? && user.authenticate(password)
  end

  def create_password_reset_token
    logger.warn "Create password reset token code goes here."
    false
  end

end
What we need to do is to create a file in the app/models/concerns folder called authentication.rb (app/models/concerns/authentication.rb) and place the following code in it :

module Authentication
  extend ActiveSupport::Concern

  included do
    has_secure_password
  end

  module ClassMethods
    def authenticate(email, password)
      user = find_by_email(email)
      user if user && user.authenticate(password)
    end
  end

  def create_password_reset_token
    logger.warn "Create password reset token code goes here."
    false
  end

end
Now, let’s refactor the User model to use the new code. Change the users model (app/models/user.rb) so that it looks like this:

class User < ActiveRecord::Base
  include Authentication
end
Now if you start the rails server and attempt to authenticate, you’ll notice that the functionality hasn’t changed at all. That’s the idea!
You can use this method for organizing and DRYing up your code!
Now let’s examine this code step by step:
  • The extend ActiveSupport::Concern tells rails that we are creating a concern;
  • The code contained in the included block will be executed within the context of the class that is including the module. This is perfect in order to use functionality provided by 3rd party gems, etc;
  • Next, you will notice the module ClassMethods block;
  • The code contained within this block will be added to the Class itself. For example, the code above adds an authenticate function to the User class. This allows you to do User.authenticate (email, password) instead of User.find_by_email(email).authenticate(password).
  • Finally, you will see the last bit of code, the create_password_reset_token function. Code not included in the ClassMethods block or the included block will be included as instance methods.
For example :
You could do @user = User.find(params[:id]) and then do @user.create_password_reset_token to create a password reset token for the specified user.
Now, all of this is great, but actually what benefit do you get from organizing your code in this fashion?
Well, let’s look at a good example of how utilizing this functionality of Rails can save you time and make your code much cleaner. What if we have a number of different models, BlogPosts, Articles, Comments, etc. and we want to add tagging functionality that will allow the user to tag each object as something.
Utilizing concerns we can quickly and easily do this :

module Taggable
  extend ActiveSupport::Concern

  included do
    has_many :taggings, as: :taggable, dependent: :destroy
    has_many :tags, through: :taggings
  end

  def tag_names
    tags.map(&:name)
  end

end
In this example, you’ll see that simply including Taggable on your modules will (with the database structure in place of course) make your models taggable. This code can quickly and easily be spread upon as many models as needed.

Well, that’s it!

Concerns are a great way to keep your code organized and DRY.

Post a comment