Zenn
Open4

RailsのForm Objectについて

ダン@HyperFormダン@HyperForm

なぜ使うのか

Railsのフォームは基本的にモデルに依存している。
1つのフォームで複数モデルの操作をしたいときにForm Objectを使うと、処理がすっきりかける。
またログインに関する処理など、特定のフォームでしか行わない処理もForm Objectに書くと良い。

ダン@HyperFormダン@HyperForm

ユースケース

  • 1つの記事に複数の画像を保存する処理(記事 has_many 画像 な関係)
  • ユーザーのログイン処理
ダン@HyperFormダン@HyperForm

使い方

appディレクトリにformsディレクトリを作る

$ mkdir app/forms

form objectを作る

$ touch app/forms/make_post_form.rb
app/forms/make_post_form.rb
class MakePostForm
  include Virtus.model
  include ActiveModel::Model # 通常のモデルのようにvalidationなどを使えるようにしたいのでActiveModel::Modelをinclude
  extend CarrierWave::Mount # モデル以外でCarrierWaveを使いたいときはこのModuleをextendする

  # 使いたい属性を定義
  attribute :title, String
  attribute :content, String
  attribute :image1, String
  attribute :image2, String
  attribute :image3, String
  attribute :image4, String
  attribute :image5, String

  # 画像アップロード機能なので、uploaderをマウント
  mount_uploader :image1, ImageUploader
  mount_uploader :image2, ImageUploader
  mount_uploader :image3, ImageUploader
  mount_uploader :image4, ImageUploader
  mount_uploader :image5, ImageUploader

  # バリデーション
  validates_presence_of %i(
    title
    content
    image1
  )

  # 保存のしかたを定義
  def save_post!
    post = Post.new(title: title, content: content).save!
    post.images.build(name: image1).save!
    post.images.build(name: image2).save! if image2
    post.images.build(name: image3).save! if image3
    post.images.build(name: image4).save! if image4
    post.images.build(name: image5).save! if image5
    return post
  end
end

controllerで呼び出し

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def new
    @post_form = MakePostForm.new
  end
  
  def create
    @post_form = MakePostForm.new(post_params)
    if @post_form.save_post!
      redirect_to post_url
    else
      render :new
    end
  end

  private

  def post_params
    params.require(:make_post_form).permit(
      :title, :content, :image1, :image2, :image3, :image4, :image5
    )
  end
end

viewでformを実装

app/views/posts/new.html.erb
<%= form_with model: @post_form, url: posts_path, local: true do |f| %>
  <%= f.text_field :title, placeholder: 'タイトル' %>
  <%= f.text_field :content, placeholder: 'コンテンツ' %>
  <%= f.file_field :image1 %>
  <%= f.file_field :image2 %>
  <%= f.file_field :image3 %>
  <%= f.file_field :image4 %>
  <%= f.file_field :image5 %>
  <%= f.submit %>
<% end %>
ログインするとコメントできます