Having a debate about better coding practices is a healthy part of growth for any developer, especially within opinionated frameworks like Ruby on Rails. One feature that often sparks discussion is the use of ActiveSupport::Concern.
To illustrate, 37signals recently released Writebook, showcasing effective use of controller and model concerns. They adhered to Rails conventions without creating different folder structures or combining related classes in one file to minimize file count. Instead, they followed the Rails doctrine of convention over configuration. While it’s not mandatory to mimic their approach, having a consistent convention in place is beneficial, allowing flexibility in how you implement it.
The debate about using ActiveSupport::Concern is not new, and it won't be the last. Opinions on its use often come from personal preferences or company policies rather than understanding why Rails includes it and its merits or drawbacks.
While I set to do further reading about it, to form my own reasoning, I received an email from Hrishi Mittal's Learnetto newsletter. He sent out a quiz for Rails developer and the first question was about concern, what a coincidence.
- What is the purpose of the `ActiveSupport::Concern` module in Rails?
- To handle HTTP requests and responses
- To manage database migrations
- To define model associations
- To provide a way to extend classes with reusable functionality
What is the correct answer?
——
To address Hrishi's question directly, let's check Rails' Concerns.
The ActiveSupport::Concern module in Rails serves several important purposes, primarily focused on enhancing the readability and organization of Ruby classes, especially models and modules. It provides a cleaner, more elegant syntax for declaring class-level methods and extending classes with additional functionality. Here are key benefits of using ActiveSupport::Concern:
1. Class-Level Methods
ActiveSupport::Concern allows you to define class-level methods directly within the module or class definition itself, without needing to open the class beforehand. This makes the code more concise and easier to read.
1. Class-Level Methods
ActiveSupport::Concern allows you to define class-level methods directly within the module or class definition itself, without needing to open the class beforehand. This makes the code more concise and easier to read.
module Commentable extend ActiveSupport::Concern included do # Class-level methods go here end def comments_count # Instance method implementation end end class Post < ApplicationRecord include Commentable end
2. Mixins Without Opening Classes
ActiveSupport::Concern simplifies including modules in classes by avoiding the need to explicitly open the class. This is particularly useful for adding behaviours to models or other classes without altering their source code directly.
module Logger extend ActiveSupport::Concern included do before_action :log_action end private def log_action Rails.logger.info("Action #{action_name} performed on #{model_name.humanize.downcase}") end end class Post < ApplicationRecord include Logger end # Creating a post and performing actions on it will now be logged. post = Post.create!(title: "Ruby on Rails Tutorial", body: "Learn Ruby on Rails the easy way.") post.update(body: "Updated content.") # This action will be logged.
3. Automatic Inclusion of Dependencies
When you include a module that extends ActiveSupport::Concern, Rails automatically includes any dependencies listed in the :include option. This reduces boilerplate code and keeps your class definitions clean.
module CommentAttributes extend ActiveSupport::Concern included do attribute :content, :string attribute :user_id, :integer end end module Commentable extend ActiveSupport::Concern included do has_many :comments include CommentAttributes end end class Post < ApplicationRecord include Commentable end # Now, when creating a comment, we can directly assign values to the attributes defined in CommentAttributes. comment = post.comments.create!(content: "Great tutorial!", user_id: current_user.id)
4. Accessible Instance Methods
ActiveSupport::Concern provides a mechanism to define accessible instance methods that can be called from the parent class. This is useful for encapsulating related methods within a module and making them accessible to the class that includes the module.
module CommentCounter extend ActiveSupport::Concern included do has_many :comments end def comments_count comments.count end end class Post < ApplicationRecord include CommentCounter end # Now, we can easily get the total number of comments on a post. post = Post.create!(title: "Ruby on Rails Tutorial", body: "Learn Ruby on Rails the easy way.") post.comments.create!(content: "Great tutorial!") # Add a comment to the post. puts "Total comments on this post: #{post.comments_count}"
5. Cleaner Syntax for Multiple Inclusions
When including multiple modules that extend ActiveSupport::Concern, you can use the :extend option to apply them all at once, resulting in cleaner and more organized code.
class Post < ApplicationRecord include Commentable include Searchable end
Final Notes…
Using ActiveSupport::Concern in your application can significantly improve code organization and maintainability. It helps you simplify how you declare class-level methods, manages dependencies, and the inclusion of modules, making your codebase more maintainable and easier to understand.
Now, can you answer Hrishi's question that we saw earlier? 👆🏼
I found myself guilty of cramming everything in a one file, or not having a enough DRY files and folders. I tell myself, it is a learning process. It needs time and consistent work.
~~~~~
I hope you enjoyed this article and learned something new! Your questions and feedback are always welcome—feel free to reply, as I'd love to hear from you.
For more articles like this, subscribe to my blog and get future posts straight to your inbox. Thank you for your support!
~~~~~
Coming to RailsWorld?
Check out my series, Ahmed’s Unofficial RailsWorld Guide to Toronto! This first-of-its-kind guide is perfect for RailsWorld attendees. I write about the history of the amazing venue, Evergreen Brickworks, take you on a ride from the airport to the city, hotels and around, and explore Toronto's best spots to eat, visit, and have fun. Whether you're attending the conference or just visiting the city, you'll find something valuable.
Yours,
Ahmed Nadar