This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the architecture category.
Last Updated: 2024-11-23
module Taggable
extend ActiveSupport::Concern
included do
has_many :taggings, as: :taggable, dependent: :destroy
has_many :tags, through: :taggings
end
def tag_names
tags.map(&:name)
end
end
class Post
include Taggable
end
class Product
include Taggable
end
class Person
include Searchable
include Visible
include Trashable
end
This means the class is gonna be better organized internally.
Some of the service classes common in the Rails world become so abstract they
are hard to understand. Usually they end with the letters -er
- e.g.
TagAdder
, TagEditer
, FileTrasher
etc.
# Extracting to a stand-alone query object
Viewer.visible(current_account.posts, to: current_user)
# vs.
curent_account.posts.visible_to(current_user)
# thanks to following concern
module Visible
extend ActiveSupport::Concern
module ClassMethods
def visible_to(person)
...
end
end
end
I had concerns for user authentication password resets, tracking etc., and these were easily ported to my other Rails apps.
This means, among other things, mocking will suck.
If you don't try to avoid this, this could leads to tests that require more stubbing to avoid callback issues that have little to do with that concern.
Henning Koch argues in some code bases you get scared to save a record because "who knows what could happen?" (Though I'd say they failed to be careful with idempotency)
Not an issue, however, with project-wide grep.
Also, can be avoided by in-lining the concern definitions
class User
module Visible
...
end
include Visible
end