The default Rails 4 project generator now creates the directory "concerns" under controllers and models. I have found some explanations about how to use routing concerns, but nothing about controllers or models.
I am pretty sure it has to do with the current "DCI trend" in the community and would like to give it a try.
The question is, how am I supposed to use this feature, is there a convention on how to define the naming / class hierarchy in order to make it work? How can I include a concern in a model or controller?
This post helped me understand concerns.
In concerns make file filename.rb
For example I want in my application where attribute create_by exist update there value by 1, and 0 for updated_by
after that include in your model like this:
So I found it out by myself. It is actually a pretty simple but powerful concept. It has to do with code reuse as in the example below. Basically, the idea is to extract common and / or context specific chunks of code in order to clean up the models and avoid them getting too fat and messy.
As an example, I'll put one well known pattern, the taggable pattern:
So following the Product sample, you can add Taggable to any class you desire and share its functionality.
This is pretty well explained by DHH:
It's worth to mention that using concerns is considered bad idea by many.
Some reasons:
include
method, there is a whole dependency handling system - way too much complexity for something that's trivial good old Ruby mixin pattern.Concerns are easy way to shoot yourself in the leg, be careful with them.
I have been reading about using model concerns to skin-nize fat models as well as DRY up your model codes. Here is an explanation with examples:
1) DRYing up model codes
Consider a Article model, a Event model and a Comment model. An article or an event has many comments. A comment belongs to either Article or Event.
Traditionally, the models may look like this:
Comment Model:
Article Model:
Event Model
As we can notice, there is a significant piece of code common to both Event and Article. Using concerns we can extract this common code in a separate module Commentable.
For this create a commentable.rb file in app/models/concerns.
And now your models look like this :
Comment Model:
Article Model:
Event Model:
2) Skin-nizing Fat Models.
Consider a Event model. A event has many attenders and comments.
Typically, the event model might look like this
Models with many associations and otherwise have tendency to accumulate more and more code and become unmanageable. Concerns provide a way to skin-nize fat modules making them more modularized and easy to understand.
The above model can be refactored using concerns as below: Create a
attendable.rb
andcommentable.rb
file in app/models/concerns/event folderattendable.rb
commentable.rb
And now using Concerns, your Event model reduces to
* While using concerns its advisable to go for 'domain' based grouping rather than 'technical' grouping. Domain Based grouping is like 'Commentable', 'Photoable', 'Attendable'. Technical grouping will mean 'ValidationMethods', 'FinderMethods' etc
I felt most of the examples here demonstrating the power of
module
rather than howActiveSupport::Concern
adds value tomodule
.Example 1: More readable modules.
So without concerns this how a typical
module
will be.After refactoring with
ActiveSupport::Concern
.You see instance methods ,class methods and included block are less messy. Concerns will inject them appropriately for you. Thats one advantage of using
ActiveSupport::Concern
.Example 2: Handle module dependencies gracefully.
In this example
Bar
is the module thatHost
really needs. But sinceBar
has dependency withFoo
theHost
class have toinclude Foo
(but wait whyHost
want to know aboutFoo
? can it be avoided ?).So
Bar
adds dependency everywhere it goes. And order of inclusion also matters here. This adds lot of complexity/dependency to huge code base.After refactoring with
ActiveSupport::Concern
Now it looks simple.
If you are thinking why cant we add
Foo
dependency inBar
module itself ? That wont work sincemethod_injected_by_foo_to_host_klass
have to be injected in class thats includingBar
not onBar
module itself.Source: Rails ActiveSupport::Concern