0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

helper/decorator/serviceについてまとめてみた

Last updated at Posted at 2023-04-26

はじめに

helperは、viewの冗長化を防いだり、コードの再利用性を高めるために使用します。
この後、説明するdecoratorもviewの改善に役立つので、何となく似ていますが、

helperはあくまでも「viewに依存している」ものです。
一方で、decoratorはモデルに依存します。

とりあえず、helperから見ていきましょう。

helper

まず、大切なことはhelperはmoduleです。クラスだと勘違いしている人がいるみたいなので注意しましょう。で、適当なhelperファイルをhelpersディレクトリ配下に作成し、以下のように独自のヘルパーを定義していきます。

helpers/user_helper.rb
module UserHelper
    def hello(name)
        "こんにちは! #{name}さん。"
    end

    def full_name
        self.last_name + " " + self.first_name
    end
end

基本的にはhelperはどのビューからでも呼び出すことができます。裏を返せば、helperに同じ名前で定義するとどれが呼び出されるか分からないので、要注意です。

例えば、以下のようにビューで書くと

test.html.erb
<%= hello("太郎") %>
<%= @user.full_name %>

以下のようにビューで表示されます。

こんにちは! 太郎さん。
太郎田中

decorator

helperが分かったところで、次はdecoratorです。

これは"draper"というgemをインストールする必要があります。
1.'draper'をインストール

# Gemfile
gem 'draper'

で、bundle installしましょう。

2.デコレーターを作成

$ rails ge decorator User

今回はフルネームを呼び出すメソッドを作っていきます。

app/decorators/user_decorator.rb

class UserDecorator < Draper::Decorator
  delegate_all

  def full_name
    "#{object.first_name} #{object.last_name}"
  end
end

例えば、Userモデルにfull_nameメソッドを定義するのではなく、
UserDecoratorを作成して以下のように実装することができます。

そして、ビューで以下のように使用することができます。

app/views/users/show.html.erb
<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を作成してみました。

app/services/user_service.rb
class UserService
  def initialize(param1, param2)
    @param1 = param1
    @param2 = param2
  end

  def execute
    # ビジネスロジックを実装
  end
end

で、このサービスをcontrollerで呼び出して使います。

app/decorators/user_decorator.rb
class UserController < ApplicationController
  def create
    service = UserService.new(param1, param2)
    service.execute
    # リダイレクトなどの処理
  end
end

UserServiceに書いているロジックをcontrollerに直接書くとあまりにも酷いことになりそうですね...
ということで、controllerを補助するためにServiceを使いましょう。ということです。

調べてみると、以下のような書き方もするみたいですが、基本的にcontrollerでnewする方が多い感じがします。個人的にもわざわざ

app/services/user_service.rb
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
app/decorators/user_decorator.rb
class UserController < ApplicationController
  def create
    service.call(param1, param2)
    # リダイレクトなどの処理
  end
end

次は、上記に絡んでくるconcernとjobについてまとめてみたいと思います!
何か修正等や改善等あればぜひ教えてください!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?