LoginSignup
214
171

More than 5 years have passed since last update.

Rails Viewの表示のためにDecoratorを用意してHelperとModelを助ける

Last updated at Posted at 2016-02-27

こんなことありませんか?

Modelの情報を少し加工してViewに表示したいことってありますよね?
例えば、ArticleというModelがあってその情報を少し加工してViewに表示したい、という以下のような場合があると思います。

<%= publication_status(@article) %>
app/helpers/articles_helper.rb
def publication_status(article)
  if article.published_at?
    "Published at #{article.published_at.strftime('%A, %B %e')}"
  else
    "Unpublished"
  end
end

ただし、これだと違和感があって、BookというモデルもArticleモデルと同じようなメソッドを作ろうとしたときに、少しだけしかフォーマットの仕方を変えないのに同じようなメソッドを作る必要が出てきます。
book_publication_statusarticle_publication_status のような2つのメソッドになるかと思いますが、グローバルな空間にこのように同じようなメソッドを作り続けるのは嫌ですね。

だったらModelで定義してしまえ!とModelで定義して下記のように呼び出すことも出来るかと思います。ただし、このメソッドはViewの表示部分のロジックを担っているわけで、その責務をModelには持たせたくない。

<%= @article.publication_status %>

そこで登場するのが Decorator というわけです。Decoratorは対応したModelのViewへの表示フォーマットのためのロジックを請け負ってくれます。

それではどのように使っていくか見ていきましょう。

以上の導入の例は以下のdraperのREADMEの導入部を使用させて頂きました。 
drapergem/draper
ただし、今回実装で使用するのは下記のactive_decoratorになります。
amatsuda/active_decorator

実際の使い方

今回、decoratorを導入するために以下のactive_decoratorを使用します。
amatsuda/active_decorator

使い方は簡単で

1. gemの 「active_decorator」をbundle

gem 'active_decorator'

2. decoratorのファイルを作成

rails g decorator article # 対応するモデルに合わせて。

3. decoratorのファイルにメソッドを記述

# app/models/article.rb
class Article < ActiveRecord::Base
end

# app/decorators/article_decorator.rb
module ArticleDecorator
  def publication_status
    if published?
      "Published at #{published_at.strftime('%A, %B %e')}"
    else
      "Unpublished"
    end
  end
end

# app/views/articles/show.html.erb
<%= @article.publication_status %>

Decoratorの利点

これまでの説明から、Decoratorの役割はイメージ出来たかと思います。Modelに対応したViewへのロジックをModelと切り離して書けていい感じですよね。
このDecoratorのいいところは、

  1. Modelに書かずにModelに対応したViewへの表示フォーマットを用意出来ること
  2. Decoratorの中にActionViewのhelperを使用することが出来ること

だと思っています。

1のほうはいいとして、2のほうはactive_recordで登場する例を用いると以下での link_toのようなhelperをDecoratorの中に直接書けるということです。
amatsuda/active_decorator

app/decorators/user_decorator.rb
module UserDecorator
  def full_name
    "#{first_name} #{last_name}"
  end

  def link
    link_to full_name, website
  end
end
app/views/users/index.html.erb
<% @users.each do |user| %>
  <%= user.link %><br>
<% end %>

なかなかに便利だと思うので是非導入して見てください

214
171
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
214
171