Introduction

As a Rails application grows, duplicated code and bloated models become a problem. Rails Concerns offer a structured way to extract reusable logic into modular components, keeping your code clean, maintainable, and DRY (Don’t Repeat Yourself).

In this guide, we will cover:

✔️ What are Rails Concerns?
✔️ How to use Concerns effectively
✔️ Best practices for modular design
✔️ Avoiding common pitfalls


1. What Are Rails Concerns?

Concerns are modules designed to extract shared behavior from models, controllers, and other parts of a Rails application.

They follow Ruby’s mixin pattern, allowing you to extend ActiveRecord models or controllers without cluttering them.

📌 Where to Place Concerns?

  • For Modelsapp/models/concerns/
  • For Controllersapp/controllers/concerns/

2. Creating a Model Concern

Example: Extracting Soft Deletion Logic

Instead of repeating soft delete logic in multiple models, extract it into a Concern.

📌 Step 1: Create the Concern file

# app/models/concerns/soft_deletable.rb
module SoftDeletable  
extend ActiveSupport::Concern

included do  
scope :active, -> { where(deleted_at: nil) }  
end

def soft_delete  
update(deleted_at: Time.current)  
end

def restore  
update(deleted_at: nil)  
end

def deleted?  
deleted_at.present?  
end  
end  

📌 Step 2: Include the Concern in Models

class User < ApplicationRecord  
include SoftDeletable  
end

class Post < ApplicationRecord  
include SoftDeletable  
end  

🚀 Why?

  • Eliminates code duplication
  • Keeps models focused on core functionality

3. Creating a Controller Concern

Example: Extracting Authentication Logic

Instead of writing authentication logic in every controller, move it to a Concern.

📌 Step 1: Create the Concern file

# app/controllers/concerns/authenticatable.rb
module Authenticatable  
extend ActiveSupport::Concern

included do  
before_action :authenticate_user!  
end

private

def authenticate_user!  
redirect_to login_path, alert: "Please log in" unless session[:user_id]  
end  
end  

📌 Step 2: Include in Controllers

class DashboardController < ApplicationController  
include Authenticatable

def index  
# Dashboard logic  
end  
end  

🚀 Why?

  • Keeps controllers lightweight
  • Ensures authentication logic is consistent across all controllers

4. Best Practices for Using Concerns

Keep Concerns focused – Each Concern should only handle one responsibility.
Use included do for ActiveRecord hooks and scopes to ensure proper execution.
Name Concerns descriptively – e.g., Loggable, Archivable, Trackable.
Avoid deep interdependencies between Concerns to keep them modular.

Avoid Fat Concerns – If a Concern grows too large, split it into multiple modules.


5. Common Pitfalls and How to Avoid Them

Overusing Concerns for Business Logic

  • If a Concern becomes too complex, consider using Service Objects instead.

Polluting the Global Namespace

  • Use descriptive names to prevent conflicts.

Adding Too Many Responsibilities to a Single Concern

  • A Concern should do one thing well. If it has multiple roles, split it into separate modules.

Conclusion

🚀 Key Takeaways:
✔️ Concerns help extract reusable code and keep Rails models and controllers clean.
✔️ Model Concerns can handle scopes, callbacks, and shared logic.
✔️ Controller Concerns improve modularity by encapsulating common filters and methods.
✔️ Follow best practices to keep Concerns maintainable and scalable.

🔗 Next Steps: Explore Service Objects for even more organized business logic!