3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】 Formオブジェクトを使ってみた感想

Last updated at Posted at 2022-10-05

背景

Formオブジェクトめちゃめちゃ便利だな〜と思ったので、まとめました。
開発環境は「Rails7」です。

Formオブジェクトとは?

FormとModelの役割を分ける時に使用するオブジェクト

Modelに依存しないので、複数のモデルを更新する専用フォームとかが作れる

Formオブジェクトを使うとき

  • 1つのフォームで複数のモデルを更新したいとき
  • 複雑なフォームの場合

今回のケース

記事と画像(1:多)を投稿するフォームを作成する。

# post.rb
class Post < ApplicationRecord
    belongs_to :user
    has_many :photos, dependent: :destroy
    validates :caption, presence: true
end
# photo.rb
class Photo < ApplicationRecord
    belongs_to :post
    validates :image, presence: true
    mount_uploader :image, ImageUploader    #アップローダー
end

1. フォームオブジェクトの作成

フォームオブジェクトは、 app/formsに作成することが推奨されている
***_form.rb

作成したフォームオブジェクト

Formオブジェクト内に、保存が必要になる、属性・バリデーションを全て定義する

class PostPhotosForm
    include ActiveModel::Model      # モデルの機能を利用するために記載
    include ActiveModel::Attributes # モデルの機能を利用するために記載
    extend CarrierWave::Mount       # アップローダーの使用

    # 属性の定義
    attribute :caption, :string     # Post
    attribute :user_id, :integer    # Post
    attribute :image, :string       # Image

    # Carrier Wave アップローダー
    mount_uploader :image, ImageUploader

    # バリデーション
    validates :caption, presence: true
    validates :image, presence: true
    validates :user_id, presence: true

    # レコードの保存
    def save
        # bool値を返す
        return false if invalid?

        # トランザクション処理
        ActiveRecord::Base.transaction do
            post = Post.create!(caption: caption, user_id: user_id)
            post.photos.build(image: image).save!
        end
    end
end

2. ビューの作成

Formオブジェクトのインスタンスを指定

 <%= form_with(model: @post_photos, url: posts_path, local: true, data:{turbo: false}) do |f| %>
  <%= f.label :caption %>
  <%= f.text_field :caption %>
  <%= f.file_field :image %>
  <%= f.submit "投稿", class: "btn btn-primary" %>
<% end %> 

3. コントローラー

ストロングパラメータを定義

class PostsController < ApplicationController
    before_action :authenticate_user!

    # 記事の作成画面
    def new
        @post_photos = PostPhotosForm.new
    end

    # 記事作成処理
    def create
        @post_photos = PostPhotosForm.new(post_photos_params)

        if @post_photos.save
            redirect_to root_path, flash: {notice: '投稿が保存されました'}
        else
            flash[:alert] = "投稿に失敗しました"
            render :new, status: :unprocessable_entity
        end
    end

    private
    # PostPhotosForm ストロングパラメータ
    def post_photos_params
        params.require(:post_photos_form).permit(:caption, :image).merge(user_id: current_user.id)
    end
end

補足(バリデーションメッセージ)

通常のモデルと同様の記載方法

<ul>
    <% @post_photos.errors.full_messages.each do |error| %>
      <li><%= error %></li>
    <% end %>
</ul> 

まとめ

モデルから責務を分離できるのは便利ですね。
大規模なフォームなどで積極的に活用していきたい。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?