Form Objectって何。
PF進捗報告会お疲れ様でした〜映画の予告編共有、コンビニ飯レコメンド、乃木坂46の推しメンレコメンド、みなさん個性的だったな〜参考になるコードを散見したから自分のPF作成に参考にさせていくことにします〜
さて、今回はFormObjectについて取り扱っていこうと思う。
FormObjectとは
>単一のフォーム送信で複数の ActiveRecord モデルを更新したい場合に、その永続化ロジックをカプセル化できるデザインパターン。
ActiveModel::Model というモジュールを include することで利用できる。
永続化ロジックとは
>dbに保存するかしないかを判断するロジックのこと。DBに保存することを永続化させると言う。
ActiveModelとは
>Activerecordを継承しないクラスでもActiveRecordと同じような便利メソッドが使えるようになる優れもの。
Ruby におけるObject Relation Mapping(ORM)
FormObjectを使用するメリット
単一のフォーム送信を作成する時にFormObjectを使わない場合、validationに必要なコードが多くなってしまう。
一方で、FormObjectを作成した場合、モデルを作成した場合とほとんど同じような記述で事足りるようになる。そのおかげで、可読性が向上する。
具体的には、formobjectを作成したいモデルに、下記コードを付け加えてあげる。
class SearchArticlesForm
include ActiveModel::Model
include ActiveModel::Attributes
例えばsignup_form.rbを作成したい場合は下記のようにかく。
class SignupForm
include ActiveModel::Model
include ActiveModel::Attributes
include Nickname
include Email
include CryptedPassword
attr_reader :user
attribute :nickname, :string
attribute :email, :string
attribute :password, :string
attribute :password_confirmation, :string
バリデーションを作成(dbにdataを保存しない)
Form Objectを使用しない場合
class FeedbacksController < ApplicationController
def new
end
def create
if params[:title].present? && params[:body].present?
AdminMailer.feedback(params[:title], params[:body]).deliver_later
redirect_to home_path, notice: 'フィードバックを送信しました'
else
@error_messages = []
@error_messages << 'タイトルを入力してください' if params[:title].blank?
@error_messages << '本文を入力してください' if params[:body].blank?
render :new
end
end
end
<%= form_with url: feedbacks_path, local: true do %>
<% @error_messages && @error_messages.each do |message| %>
<%= message %>
<% end %>
<%= label_tag :title %>
<%= text_field_tag :title, params[:title] %>
<%= label_tag :body %>
<%= text_area_tag :body, params[:body] %>
<%= submit_tag %>
<% end %>
Form Objectを使用した場合
class Feedback
include ActiveModel::Model ・・・①
attr_accessor :title, :body ・・・②
validates :title, :body, presence: true ・・・②
def save
return false if invalid?
AdminMailer.feedback(title, body).deliver_later
true
end
end
①ActiveModelを継承することで、validatesを使うことができる。
②セッターとゲッターを一気に定義している
③ @error_messages << 'タイトルを入力してください' if params[:title].blank?と
@error_messages << '本文を入力してください' if params[:body].blank?
を短縮させている。
class FeedbacksController < ApplicationController
def new
@feedback = Feedback.new
end
def create
@feedback = Feedback.new(feedback_params)
if @feedback.save
redirect_to home_path, notice: 'フィードバックを送信しました'
else
render :new
end
end
private
def feedback_params
params.require(:feedback).permit(:title, :body)
end
end
<%= form_with model: @feedback, local: true do |f| %>
<% if @feedback.errors.any? %>
<% @feedback.errors.full_messages.each do |message| %>
<%= message %>
<% end %>
<% end %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
ActiveRecordを継承させることで、永続化ロジックをスッキリ書くことができた。
@error_messages = []
@error_messages << 'タイトルを入力してください' if params[:title].blank?
@error_messages << '本文を入力してください' if params[:body].blank?
//下記記述だけで上記コードの役割を果たす。
validates :title, :body, presence: true
form objectを使ってみよう - メドピア開発者ブログ
Rails Design Patterns: Form Object
肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
GitHub - solnic/virtus: [DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects