Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Railsでロジックを書く場所を意識する

More than 5 years have passed since last update.

ロジックの分割

対象バージョン

  • Ruby 2.2.2
  • Ruby On Rails 4.2.3

ロジックを書く場所

言語を問わずMVCのフレームワークを使う時に以前からよく言われていた話として、ビジネスロジックをコントローラに書いてはいけないというのがあります。
しかし、単にコントローラを薄くすることだけを考えるとモデルがFatになってきたりするので、モデルに切り出すという事以外にもいくつかの方法を知っておく必要があります。

実装のパターン

1.モデルに実装する

コントローラにコードを書くのではなく、モデルにビジネスロジックを実装してコントローラを薄くします。
ただし、モデルにコードを集約し過ぎるとモデルがFatになってしまうので、本当にモデルに実装すべきかをよく考え、他の層に切り出すことも考えます。

モデルに実装するパターン

  • モデルに紐付いたテーブルのレコード取得(ActiveRecordの操作)
  • モデルに紐付いたテーブルをベースとした関連テーブルを含めたデータ取得
  • モデルに紐付いたテーブルのデータ更新

単一テーブルの単純な更新など、シンプルな処理が該当すると思います。

2.フォームクラス

ビュー上の項目とモデルの項目に差異がある場合など、それを吸収させるものとしてモデルとビューの間にフォームクラスを差し込みます。

フォームクラスの実装例

フォームクラスはActiveModelをIncludeして実装することで、DB側に無いテーブルやテーブルの項目などの扱いが簡単になります。

例えば入力された内容のメールを送るだけのFAQ画面があった場合、以下のようにフォームクラスを定義することでバリデーションをかけることも可能です。

class FaqForm
  include ActiveModel::Model
  attr_accessor :message

  validates :message, presence: true, length: { maximum: 1000 }

  def send
     ....
  end
end

ActiveModelをIncludeしているので、valid?メソッドなども使えます。

  @faq_form = FaqForm.new(faq_form_params)

   if @faq_form.valid?
    ....
  end

3.サービスクラス

複数のモデル操作やファイル操作などの処理を、アトミックなビジネスロジックのひとまとめの単位としてサービス層として切り出します。

サービスクラスの実装例

以下のように通常のクラスを定義します。

class DataRegistrationService
  def initialize
    ....
  end

  def registrate
    ....
  end
end

4.Concern

モデルやコントローラ間でしか使わないような共通処理はそれぞれのconcernに切り出します。

concernのディレクトリ

  • app/models/concerns
  • app/controllers/concerns

実装例

app/model/member.rb
class Member
  include User
end
app/model/concerns/user.rb
module User
  extend ActiveSupport::Concern

  included do
    attr_accessor :user_name
    def self.default_user_name
      "名無しさん"
    end

    def default_user_name?
      uesr_name == self.class.default_user_name
    end
  end
end

5.ヘルパの活用

ビュー側で使うような見た目に関するものはヘルパで実装します。
例えば名前に敬称をつける場合など。

module UsersHelper
  def display_name(firstname, lastname)
    "#{lastname} #{first name} さん"
  end
end

ただし、苗字 + 名前 でフルネームみたいなものは、モデル側でメソッドを実装して仮想化カラムのように扱うこともあります。

6.DraperなどのGemを使う

モデルとビューの中間に位置するようなプレゼンター層を扱えるGemもいくつか出ているのでそれを使うのも選択肢としてあると思います。

lanches
ブランドとファンを繋ぐクラウドプラットフォーム「EAP」の開発をしています。
https://www.lanches.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away