はじめに
helperは、viewの冗長化を防いだり、コードの再利用性を高めるために使用します。
この後、説明するdecoratorもviewの改善に役立つので、何となく似ていますが、
helperはあくまでも「viewに依存している」ものです。
一方で、decoratorはモデルに依存します。
とりあえず、helperから見ていきましょう。
helper
まず、大切なことはhelperはmoduleです。クラスだと勘違いしている人がいるみたいなので注意しましょう。で、適当なhelperファイルをhelpersディレクトリ配下に作成し、以下のように独自のヘルパーを定義していきます。
module UserHelper
def hello(name)
"こんにちは! #{name}さん。"
end
def full_name
self.last_name + " " + self.first_name
end
end
基本的にはhelperはどのビューからでも呼び出すことができます。裏を返せば、helperに同じ名前で定義するとどれが呼び出されるか分からないので、要注意です。
例えば、以下のようにビューで書くと
<%= hello("太郎") %>
<%= @user.full_name %>
以下のようにビューで表示されます。
こんにちは! 太郎さん。
太郎田中
decorator
helperが分かったところで、次はdecoratorです。
これは"draper"というgemをインストールする必要があります。
1.'draper'をインストール
# Gemfile
gem 'draper'
で、bundle installしましょう。
2.デコレーターを作成
$ rails ge decorator User
今回はフルネームを呼び出すメソッドを作っていきます。
class UserDecorator < Draper::Decorator
delegate_all
def full_name
"#{object.first_name} #{object.last_name}"
end
end
例えば、Userモデルにfull_nameメソッドを定義するのではなく、
UserDecoratorを作成して以下のように実装することができます。
そして、ビューで以下のように使用することができます。
<h1><%= @user.decorate.full_name %></h1>
こうすることで、Userモデルにロジックを持たせずに、ビューで必要な情報を提供することができます。
ただし、decoratorを使用する場合は、新しいオブジェクトが生成されるため、パフォーマンスに少し影響が出る可能性があります。
ここでふと疑問が...
「helperとdecoratorのどっちでも良くない?」と。
確かに、どちらも同じようなことをやっているので、どちらもいい気がします。
ただし、使い分けは冒頭でも伝えた通り、以下の通りです。
- helperは「ビューに依存」
- decoratorは「モデルに依存」
個人の見解
helperはあくまでもビューでよく使われる繰り返し処理や条件分岐などの定義をするもので、モデルには依存させない方が良いです。その方がdecoratorとの境界線をひけるので、開発でも「どこに書いたらいいかな?」という疑問が生まれにくくなると思います。
例えば、今回、full_nameメソッドをhelperとdecoratorのどちらでも定義しましたが、このメソッドはモデルに依存しているので、decoratorに書くのが良いと個人的には思います。
また、helperはどこからでも呼び出せてしまうので、decoratorに書くことで、「このモデルのメソッドだよ!」と共通理解がしやすいかと思います。個人開発なら良いですが、チーム開発をしているとhelperの名前を被せないようにすることは無駄な労力です。
ただ、調べていると、結局のところチームや個人の方針によるところも大きいみたいなので、その運用方針に合わせていけば良いんじゃないかなと思いました。
service
続いては、Serviceについてです。
これまで見てきたように、helperとdecoratorはビューの補助的存在でした。
要は、ビューがぐちゃぐちゃになって読みづらい!という状況をなくすために、使用するわけですね。
(極論を言えばビューの中に全て書いてもいいわけです...)
一方で、このserviceはcontrollerの補助的存在と言えます。
主にControllerから呼び出されます。また、複数のモデルにまたがる処理を実行する必要がある場合や、外部APIを呼び出す必要がある場合にも使用されます。
書き方は以下の通りです。今回はUserServiceを作成してみました。
class UserService
def initialize(param1, param2)
@param1 = param1
@param2 = param2
end
def execute
# ビジネスロジックを実装
end
end
で、このサービスをcontrollerで呼び出して使います。
class UserController < ApplicationController
def create
service = UserService.new(param1, param2)
service.execute
# リダイレクトなどの処理
end
end
UserServiceに書いているロジックをcontrollerに直接書くとあまりにも酷いことになりそうですね...
ということで、controllerを補助するためにServiceを使いましょう。ということです。
調べてみると、以下のような書き方もするみたいですが、基本的にcontrollerでnewする方が多い感じがします。個人的にもわざわざ
class UserService
class << self
def call(param1, param2)
new(param1, param2).execute
end
end
def initialize(param1, param2)
@param1 = param1
@param2 = param2
end
def execute
# ビジネスロジックを実装
end
end
class UserController < ApplicationController
def create
service.call(param1, param2)
# リダイレクトなどの処理
end
end
次は、上記に絡んでくるconcernとjobについてまとめてみたいと思います!
何か修正等や改善等あればぜひ教えてください!