HelperとDecoratorの使い分け
はじめに
先日、会社の人からHelperとDecorator(デコレーター)の違いについて教えてもらったのでメモがてらまとめてみます。
両者とも共通しているのはビューにロジックを書かないために使われるものですね。
RubyというかRailsにおいてビューの役割はコントローラーから渡されたデータを表示するだけなので、データを加工したり操作をしてはいけません。
なのでロジックに関するものはhelperで全部書いてしまえばいいのではないかと思いますが、そうなるとHelperがfat化になる可能性もあるし、単一責任の原則を厳密には守れていないみたいです。
この時に使うのがDecoratorになります。
両者をどのように使い分けるかですが、HelperはModelに依存しないロジック、DecoratorはModelに依存するロジックをそれぞれ書きます。
Modelに依存しないロジックとは日時表示やparamsなどで、Modelに依存するロジックとはその名の通りModelのデータ表記に関するものです。
ModelとHelperとDecoratorの関係図
説明ばかりしてもわかりづらいのでコードを書いてみます。
Helper
まずはHelperからです。
今回はHelperには日にちのロジックを書きます。
app/helpers/application_helper.rb
module ApplicationHelper # 受け取った引数を年月日曜日で表示するメソッド def year_month_day(date) date.strftime("%Y年%m月%d日(#{%w(日 月 火 水 木 金 土)[date.wday]})") end end
ビュー(Haml)
= year_month_day(Time.now)
ブラウザではこのような表記になります。
Decorator
次にDecoratorです。
Decoratorを使うためにはdraperというgemをインストールする必要があります。
gemfile
gem 'draper'
今回はすでにモデルは定義されているので、rails g decoratorでDecoratorファイルを作成します。
$ rails g decorator 作成したいファイル名
Decoratorファイルにメソッドを定義します。
app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator delegate_all # Userテーブルに紐付いているlevelテーブルのidによって条件分岐をして表示する値を変える。 def post_ranking if level.id > 10 "すごい" else "まだまだだね" end end end
次にビューファイルで呼び出します。
app/views/users/show.html.haml
#(htmlの)クラス名=インスタンス変数(呼び出し元は状況に応じて変わる).Decoratorで定義されたメソッド .user-content__questions=@user.post_ranking
これでブラウザを表示するとこうなります。
うーん、定義しているのに定義していないと言われますね。。。
調べるとコントローラでインスタンスに対してdecorateをつけるとDecoratorファイルに定義されたメソッドが呼び出すことができるようになります。
コントローラでメソッドを呼び出したいインスタンスにdecorateをつけてみます。
app/controllers/users_controller.rb
class UsersController < ApplicationController def show @user = User.find(params[:id]).decorate end end
再度、ブラウザを読み込みます。
おっ!ちゃんと呼び出されていますね!
これはdecorateをつけることでモデルのインスタンスをDecoratorクラスのインスタンスに変えること(モデルをDecoratorに組み込む)で、Decoratorファイルのメソッドを使えるようにしているってことなのかな(自信ない)
イメージとしてはこんな感じ
Decoratorファイル内にあるdelegate_allはモデルにあるメソッドをDecoratorクラスにも使えるようにするための記述のようです。
この記事を書いた段階での、自分の中での使い分け基準としてはインスタンス.メソッドで呼び出せるものはDecoratorに定義して、呼び出せないのはhelperに定義するって言われるとしっくりくるかな。
helperで定義したメソッドの引数にインスタンスを渡すのはなんか違和感あるから、Decoratorは使ったほうがいいなと思いました。
まとめ
・HelperはModelに依存しないロジックを書く
・DecoratorはModelに依存するロジックを書く