Yes, concerns are just modules, yet they’re also more than that. They’re also about a style of project organization. So they’re really doing a lot of work, and no wonder it’s confusing! And just like it’s not always obvious that app/models can contain POROs or other non-db backed models, it’s not obvious that app/models/concerns isn’t really where you’d put most concerns.
I’m extracting from DHHs screencast here.
We have an Active Record model that includes a concern, here expressed as just a module
, which wraps a PORO for a nicer call API. All namespaced within User::
and app/models/user
. This is how the vast majority of models at Basecamp look, for instance.
Note: this is about the organization, not so much the content within, in the real app there’d be more code in these pieces.
# app/models/user.rb
class User < ApplicationRecord
include Notifiee
end
# app/models/user/notifiee.rb
module User::Notifiee
# Philosophically a concern, i.e. a role a model can play, but:
# extend ActiveSupport::Concern is not needed without included/class_methods calls.
def notifications
@notifications ||= User::Notifications.new(self)
end
end
# app/models/user/notifications.rb
class User::Notifications
attr_reader :user
delegate :person, to: :user
def initialize(user)
@user = user
end
end
I totally wish we had some more documentation or tooling that could push you in this direction or make it more obvious how this could work — perhaps in guides or generators.