79
59

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 5 years have passed since last update.

ニフティグループAdvent Calendar 2018

Day 16

【Rails】FormObjectを使ってほしい

Posted at

RailsでForm Objectを導入はするのは今となっては珍しくもないかと思います。
それでも組織やチームに文化がない状態で投入してしまうと
それ自体が負債となる場合もあるんだろうなと感じたところもありました。

今回は普及のためにもForm Objectを作る方法を紹介してみようと思います

Form Objectとは?

単体のモデルに依存しない場合や
フォーム専用の特別な処理をモデルに書きたくない場合に用いたりします。

例えば1つのフォーム送信で複数のモデルの更新をしたい場合
バリデーションの責務が曖昧なものとなり関心事が多くなり
忘れたときに改めて解読するのも嫌になってしまうことがあります。
そのためにも責務を明確にするのは個人的には大切かなと。

責務ばかりを気にしていたら速度が失われてしまうため
状況を見つつ使い分けはしたいところ。。

メリットはあるか?

どんなに便利な手法だとしても
用法用量を守って触らないとろくな事にならないのはお察し。。
気を取り直してどういうメリットが有るかですが

  • ActiveRecordと同じバリデーションを使うことができる
  • Form Objectにパラメーターをそのまま渡すことができるためエラーメッセージを戻す処理が書きやすい
  • 責務がモデルとは言い切れないビジネスロジックをcontroller/viewから切り離せる
    • いわゆる単一責務の状態となりやすい

##ユースケース

  • ユーザからの問い合わせを受け付けるフォームを実装したい
  • 未登録ユーザは氏名とメールアドレス、内容の取得と通知を目的とする

最初はこれでよかったのかもしれない。
ただ実際にふたを開けてみたら
登録済みのユーザはIDと内容だけがいいとか
そもそも入力項目を増やしたいだとか経験がありますよね。

##Form

まずは今回の用件以外の関心ごとを減らすためにも
Form Objectの定義します

app/forms/contact_form.rb

class ContactForm
  include ActiveModel::Model

  attr_accessor :first_name, :last_name, :email, :body

  validates :first_name, presence: true
  validates :last_name, presence: true
  validates :email, presence: true
  validates :body, presence: true

  def save
    return false if invalid?
    # 保存, 通知, ロギング等
    true
  end
end

Controller

次にControllerの処理です。
Form Objectにロジックを寄せたおかげで
scaffoldで作られようなシンプルな形を維持できます。

app/controllers/contact_controller.rb
class ContactController < ApplicationController

  def index
    # お問い合わせ一覧
  end

  def new
    @contact = ContactForm.new
  end

  def create
    @contact = ContactForm.new(set_params)
    if @contact.save
      redirect_to :contacts, notice: 'お問い合わせを受け付けました。'
    else
      render :new
    end
  end

  private

  def set_params
    params.require(:contact).permit(:first_name, :last_name, :email, :body)
  end
end

Routes

config/routes.rb
Rails.application.routes.draw do
  resources :contacts, only: [:index, :new, :create]
end

まとめ

Form Objectは一つの選択肢ですが
導入もしやすくわかりやすいのはいいところではないかと思います。
現実はこんなにシンプルには行きませんが手段として知っているだけでも選択肢が増えるかと思います。

複数人で開発を行う場合は
レイヤーの立場を明確にするなど
認識を合わせてからの導入が良いのだろうという反省のお話でした。

79
59
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
79
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?