Railsアプリケーションの規模が大きくなってくると起こりがちな問題の一つとして、「Modelにあらゆるコードが集中してしまい肥大化してしまう」ことがあります。
今回はその対策としてよく用いられるDecoratorについてご紹介します。
※このコラムのプログラム等は以下の環境で動作確認しています
(2023/11/30 最終確認)
ruby: ruby 3.2.2 [arm64-darwin22]
rails: rails (7.1.2)
active_decorator 1.4.1
表示のためのロジックをどこに書くか?
View上で「Userモデルのfirst_name
とlast_name
を結合してフルネームを表示したい」としましょう。
実現するだけであれば、Viewに直接記述できますがこれは本来Viewが持つべき機能ではありません。可読性も悪くなり、テストコードを書こうとしても煩雑になってしまいます。
app/views/users/show.html.erb
<%- # 良くない例 -%>
<%= "#{@user.last_name} #{@user.first_name}" %>
RailsではViewをシンプルに保つために、こういったロジックはHelperに書くことがより良い方法です。
app/helpers/users_helper.rb
module UsersHelper
def user_full_name(user)
"#{user.last_name} #{user.first_name}"
end
end
app/views/users/show.html.erb
<%- # Helperを使用 -%>
<%= user_full_name(@user) %>
ロジックをViewから分離することはできましたが、この場合オブジェクト指向の観点では@user.full_name
のようにインスタンスのメソッドとして参照する方が自然です。
その場合、Userモデルに実装することはできます。
app/models/user.rb
class User
def full_name
"#{last_name} #{first_name}"
end
end
app/views/users/show.html.erb
<%- # Modelのメソッドを使用 -%>
<%= @user.full_name %>
オブジェクト指向の観点では自然な形にはなりましたが、この調子で表示のためのメソッドを追加していくとModelが肥大化、どんどん大きくなってしまいます。
これを解決するための手法が、Decoratorです。
ActiveDecorator
RailsにDecoratorを導入できるGemはいくつかありますが、今回は ActiveDecoratorをご紹介します。
最初のリリースから既に12年以上を経ていますが、現在でもメンテナンスされRails7.1(edge)への対応も明記されていますので安心して使用できます。
使い方
使い方もシンプルです。Gemfile
にactive_decorator
を追加してbundleし、命名規則に従ってmoduleを作成しメソッドを実装するだけでViewから参照することができます。
User
モデルの場合、app/decorators/user_decorator.rb
ファイルに実装します。
generatorコマンドを利用した生成もできます。
bin/rails g decorator user
app/decorators/user.rb
module UserDecorator
def full_name
"#{last_name} #{first_name}"
end
end
app/views/users/show.html.erb
<%- # Decoratorのメソッドを使用(Viewのコードはそのまま、追加対応不要) -%>
<%= @user.full_name %>
使い方(Action View外)
Viewでは自動的にDecoratorが適用された状態になりますが、その他の箇所で適用して利用することもできます。
# user は通常のActiveRecordインスタンス
decorated_user = ActiveDecorator::Decorator.instance.decorate(user)
decorated_user.full_name # 利用可能
まとめ
Modelの肥大化を軽減するためのDecoratorという手法、そしてDecoratorを導入するGemとしてActiveDecoratorをご紹介しました。
Railsでの開発はどうしても特定のModelに実装が集中してしまいがちです。
その軽減のために様々な手段が長らく議論され、各々で開発手法として試されてきた経緯があります。
一方で、そういったものを次々に取り入れていくと本来のRailsアプリケーションの構成を離れ複雑になってしまい、かえって扱いづらい状況になることもあり賛否両論、という側面も存在します。
しかしDecoratorはご紹介した通りシンプルな要素であり、Railsの扱いやすさを損なわないというメリットがあります。
Modelの肥大化が少しでも気になる方は、まずは取り入れてみることをおすすめします。
お知らせ
当委員会ではRails試験を全国300か所で一年中実施をしています。興味がある方は以下をご覧の上、是非受験ください。https://railsce.com/exam