Welcome
Hello dear friends, coders and enthusiasts.
Today we are going to dive into the topic of “Concerns” in Ruby on Rails. Concerns are an important topic in Ruby on Rails but anyway, it’s up to a developer to decide whether to use them or not. And besides that, they need to be used carefully to avoid issues of so called “circular dependency” and revealing too much info of the model to the Concern.
So, let’s get started…
What does a Concern help with?
A Concern is just a ruby module that extends ActiveSupport::Concern module.
You might have already seen the folders that are created by default when creating a new Rails project. Those folders are ‘app/controllers/concerns’ and ‘app/models/concerns’. These folders are where concerns should be placed.
Using a concern lets you extract the common logic from different classes into a reusable module.
What we have to do to extract some logic into a concern is write a concern module that extends “ActiveSupport::Concern” module. So, let’s write an Archiveable concern module.
module Archivable
extend ActiveSupport::Concern
included do
scope :visible, -> { where(archived: false) }
scope :archived, -> { where(archived: true) }
end
def archive
update_attribute :archived, true
end
end
So, to use it in our models, we just need to include the above described module within our model classes.
class Post < ApplicationRecord
include Archivable
has_many :comments
# ...
end
class Comment < ApplicationRecord
include Archivable
belongs_to :post
# ...
end
As you already might have notice, this code assumes that you have ‘archived’ attribute in both of the models (‘Post’ and ‘Comment’) to operate on. Otherwise we won’t be able to use execute the intended code, because the ‘Archivable’ module makes use of ‘archived’ attribute.
Two important parts of a Concern
A concern can provide two blocks that comprise different types of methods to be used in the included class.
- included
The code inside this block is evaluated in the context of the including class. For instance, if a class ‘Comment‘ includes a concern, anything inside the ‘included’ block will be evaluated as if it was written inside the “Comment” class.
You can add validations, associations, scopes, or other methods, and all of these become instance methods of the including class.
- class_methods
All the methods added inside this block become class methods of the including class. As a second option, you can create a nested module called “ClassMethods” where you can put your class methods.
module Visible
extend ActiveSupport::Concern
# This is where you place instance methods
included do
def toggle_visibility
toggle!(:is_visible)
end
end
# This is where you place class methods
class_methods do
def get_all_visible
all.select { |item| item.is_visible? }
end
end
end
Here’s the “Visible” concern where the two above-mentioned blocks reside and we place our instance and class methods accordingly within those blocks.
Good approaches to using Concerns
- Single Responsibility Principle
A good concern should be able to work in isolation, so it must be dependency-free. It should have a very concrete and limited responsibility.
Bear in mind the Single Responsibility Principle when extracting something to a concern. That being said, you need to extract just a small, reasonable code to a concern so that it stays manageable and include’able into several locations in the future.
Construct a concern that, for instance, just manages Archive’ability, Exportability, Notifiability of a model, and not many of those features.
- Using Concerns for multiple models
It is a good approach to extract Concerns when they tend to be useful in several models. This way we are obeying the DRY principle and using the same piece of code in several models. It shrinks the code and makes it manageable.
A good example of this might be “Exportable” module/concern. This concern can be included in several models, like: Email, Document, Table, Drawing and etc… This way, it becomes a very useful accessory to use.
Conclusion
We have covered the basics of implementing concerns in Ruby on Rails and it gives you a basic idea of why’s and how to’s about using concerns.
Actually no code is perfect and it’s up to you to decide how to organize things and make the code perfectly readable. You need to use your own judgment and weigh the pros and cons of either of the options.
Hope to meet you in the next article !
Stay safe, stay healthy, stay hungry !!! 👋
Top comments (0)