RailsでGemを使わずにDecoratorを導入する方法です。
Class#inheritedを使う
コードから説明するとApplicationRecordに202511272207次のコードを実装します。
app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base primary_abstract_class
def self.inherited(subclass) super subclass.include "#{subclass.name}Decorator".constantize if Object.const_defined?("#{subclass.name}Decorator") endendhttps://docs.ruby-lang.org/ja/latest/method/Class/i/inherited.html
RubyのClass#inheritedを使って、ApplicationRecordが継承されたとき、つまりサブクラスとなるモデルクラスが定義されたときにDecoratorをincludeするようにします。
ここではRailsの設計思想であるCoC(設定より規約)を用いて、モデル名に対応するDecoratorを自動でincludeするようにしています。
例えばUserモデルの場合はUserDecoratorを定義しておけば、自動でincludeしてくれます。
わざわざUserモデルにinclude UserDecoratorとする必要はありません。
if Object.const_defined?としているので、モデル名に対応するDecoratorが定義されている場合のみinludeしているので、すべてのモデルのDecoratorを作成する必要はありません。必要なDecoratorだけ定義すればOKです。
Decoratorを定義する
ApplicationRecordで自動でDecoratorをincludeする仕組みを作ったらDecoratorを定義しましょう。
注意するのはDecoratorのmodule名です。
モデル名Decoratorの規約で命名します。
つまりUserモデルであればUserDecorator,PostモデルであればPostDecoratorとします。
Userモデルでfirst_nameとlast_nameカラムをもち、full_nameメソッドをもつDecoratorの定義例です。
app/decoratorsディレクトリを作成して、app/decorators/user_decorator.rbを定義します。
module UserDecorator def full_name "#{last_name} #{first_name}" endend規約に沿ったDecorator moduleを作るだけで、自動でincludeされます。
使ってみる
Decoratorを作成したら、試しに使ってみましょう。 ターミナルでRails consoleを立ち上げます。
rails c> user = User.new(first_name: "tomoya", last_name: "yoshida")> user.full_name #=> yoshida tomoyafull_nameがかえってきましたね。
注意点
Gemを使わないお手軽Decoratorを実装してみました。 ただしお手軽な分、注意点があります。
ActiveDecoratorなどのGemはViewでしか使えないようになっていますが、今回の実装の場合、View以外でも利用可能です。 つまりどこでも呼び出せてしまうので、本来のDecoratorの使い方をしているかどうかは利用者側に委ねられています。 私はGemを入れると更新コストがかかるので、あまりいれないようにしています。 Gemをいれるか、お手軽実装にするかはプロジェクトに合わせて判断しましょう。