h3pei.tech
お仕事のご依頼
2018-02-10

draperを使ってみた

draper というデコレーター(またはプレゼンター)の機能を持つ Gem を使ってみた記録。

draper とは

  • draper is …
    • ViewModel for Rails
    • Rails アプリケーションにオブジェクト指向なプレゼンテーション層を追加する
    • Model にメンテナンス性の高いプレゼンテーションロジックを包み込む

なぜ draper を使うのか

  • View にまつわるロジックの置き場として Helper も存在する。しかし、Helper はグローバルスコープを持っているため全ての Controller と View で利用できてしまう
  • Helper を使った場合、Model に応じた微妙な差異を吸収するために新しいメソッドが追加される
    • 例:Article モデルは日時を YYYY-MM-DD HH:mm:ss で表現したいが、Book モデルは YYYY-MM-DD で表現したい
  • Helper はオブジェクト指向に書きづらい

→ draper はこのような問題を解決する

使ってみる

セットアップ

gem 'draper' を Gemfile に追記してインストールしたら、ジェネレートコマンドを使って一式生成する。
User モデルがあるとして、それに対応する decorator を生成する。

>> bin/rails g decorator User
      create  app/decorators/user_decorator.rb
      invoke  test_unit
      create    test/decorators/user_decorator_test.rb

app 以下に decorators ディレクトリが作成され、その下に user_decorator.rb が追加された。

デコレートメソッドを追加する

早速 User モデルをデコレートしていく。
ここでは、User が自己紹介をするためのデコレートメソッドを追加した。

# app/decorators/user_decorator.rb
def greeting
  "Hi! My name is #{user.name}. I am #{user.age} years old. Thank you."
end

decorator クラス内で、対応するモデルにアクセスするには object か対応するモデル名(User モデルの場合は user)を呼び出す。

Controller でモデルをデコレートする

Model をデコレートする準備は整ったので、次は Controller で取得した Model をデコレートした上で View に受け渡す。
次のように、Model に対して decorate メソッドを呼び出すだけで OK。

# app/controllers/users_controller.rb
def show
  @user = User.find_by(id: params[:id]).decorate
end

View でデコレートメソッドを呼び出す

View ではデコレートされていることを意識する必要はなく、普通にメソッドを呼び出すだけでいい。

<!-- app/views/users/show.html.erb -->
<h1><%= @user.greeting %></h1>

画面

2018-02-10-01.png

これで draper を使った一連の実装を体感できた。

アソシエーションに対応する

関連するモデルも含めてデコレートしたい場合は、次のようにデコレータクラスで decorates_association メソッドを呼び出す。

# app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
  # ここでは、UserはN個のDeckを持つ関連が設定されているとする
  decorates_association :decks
end

これで、deck 側もデコレートされたオブジェクトとして扱うことができる

その他のメモ

  • decorator クラス内で、helper にアクセスするには h を呼び出す
    • 例:h.content_tag(:strong, user.name)
  • コレクションを decorate するいくつかの方法があるようだ
    • UserDecorator.decorate_collection(User.all)
    • User.all.decorate
    • これは具体的に何が違うのかまで調べていない
  • ApplicationDecorator などとして、Decorator 共通の処理を括りだすことができる。この場合、各デコレータクラスは Draper::Decorator ではなく ApplicationDecorator を継承するようにする
    • class ApplicationDecorator < Draper::Decorator
    • class UserDecorator < ApplicationDecorator
  • Decorator クラスはデフォルトで deltega_all が呼び出され、全てのメソッド呼び出しを委譲しているが、delgate メソッドで個別に指定することも可能
  • どのデコレータを使うかの指定も可能。デフォルトではファイル名から判定されている。
h3pei's icon

h3pei

フリーランスのソフトウェアエンジニア。Ruby / Rails アプリケーションの開発が得意領域。設計・実装・運用まで含めてプロダクト開発が好きです。

Questalという目標達成コミュニティサービスを開発しました。仲間と一緒に目標達成に取り組みたい方はぜひご利用ください。

お仕事のご依頼
GitHubnoteX

関連記事