はじめに
Ruby on RailsなどのMVCフレームワークで構築したWebシステムにはアンチパターンというものが存在します。システム開発におけるアンチパターンとは、避けるべき悪い設計や実装方法のことを指します。
MVCフレームワークでありがちなアンチパターンの一つとして「ファットコントローラー」があります。これは読んで字のごとく、コントローラーにいろいろな処理を詰め込んでしまった結果、コントローラーが肥大化してしまっている状態です。
ファットコントローラーを解消する手段として、コントローラー内の処理をモデルなどに移動する方法があります。しかし、それもいつかは限界が来て今度は「ファットモデル」という別のアンチパターンに陥る可能性が出てきます。
MVCフレームワークでは"Skinny Controllers, Fat Models"、つまり「痩せたコントローラー、太ったモデル」が推奨されています。コントローラーを太らせるよりモデルを太らせるほうがよいということです。
しかし、だからといって何千行、何万行もあるモデルでは全体の見通しが悪く、可読性・保守性が低いと言わざるを得ません。
そこで、MVCフレームワークでシステム開発を行う際には「デザインパターン」の設計が重要になってきます。コントローラーやモデルではない別のロジック層を用意し、処理を適切に分散することで可読性・保守性が向上します。
デザインパターンには多くのロジック層が存在します。この記事では「Concern」について説明します。
Concernについて
概要
Concernは、モジュールを使って関連するメソッドやコールバックをグループ化し、複数のモデルやコントローラーで再利用可能にする機能です。
Railsプロジェクトを新規作成すると、app/controllers/
配下やapp/models/
配下にconcerns/
というディレクトリが作成されています。この中にコントローラーやモデルで共通化したいモジュールを実装していきます。
module MyModule
extend ActiveSupport::Concern
included do
# ここにクラスメソッドやコールバックを記述
end
# インスタンスメソッドをここに記述
class_methods do
# クラスメソッドをここに記述
end
end
実装例
Concernを使った実装例を紹介します。
app/models/concerns/timestampable.rb
module Timestampable
extend ActiveSupport::Concern
included do
before_save :set_timestamps
end
def set_timestamps
self.created_at = Time.current if self.new_record?
self.updated_at = Time.current
end
def formatted_created_at
created_at.strftime("%Y-%m-%d %H:%M:%S")
end
class_methods do
def recent(limit = 5)
order(created_at: :desc).limit(limit)
end
end
end
app/models/article.rb
class Article < ApplicationRecord
include Timestampable
end
app/models/comment.rb
class Comment < ApplicationRecord
include Timestampable
end
Concernを使用することで、すべてのモデルからTimestampableモジュールで定義されたメソッドやコールバックが使用できるようになります。
まとめ
Concernの注意点として以下が挙げられます。
- Concernの過剰な使用は避ける(モデル間の結合度が高くなりすぎる可能性がある)
- 適切な粒度でConcernを作成する(大きすぎず、小さすぎず)
Concernを適切に使用することで、Railsアプリケーションのコードをより整理され、保守しやすいものにすることができます。