最近FormObjectを作ろうと思って調べてみたところ、ネット上の記事だと #update
ができなかったり、Ruby 3.0 だとそのまま動かなかったりしたので、需要があるかと思い作成しました。
まだまだ色々改善点があるので、元のリポジトリの方でもう少し改善していこうと思っています。
また、FormObject自体に関する説明は、こちらのサイト(Railsのデザインパターン: Formオブジェクト)によくまとまっているので、ご参照ください。🙏
モデル
class Post < ApplicationRecord end
フォーム
class PostForm include ActiveModel::Model attr_accessor :title, :content validates :title, presence: true delegate :persisted?, to: :post def initialize(post = Post.new, **attributes) @post = post attributes = { title: post.title, content: post.content } if attributes.empty? super(attributes) end def save return if invalid? post.update!(title: title, content: content) rescue ActiveRecord::RecordInvalid false end def update(params) self.attributes = params save end def to_model post end private attr_reader :post end
コントローラー
class PostsController < ApplicationController def index @posts = Post.all end def show @post = post end def new @post_form = PostForm.new end def edit @post_form = PostForm.new(post) end def create @post_form = PostForm.new(**post_params) if @post_form.save redirect_to posts_path, notice: 'The post has been created.' else render :new end end def update @post_form = PostForm.new(post, **post_params) if @post_form.save redirect_to post, notice: 'The post has been updated.' else render :edit end end def destroy post.destroy redirect_to posts_url, notice: 'Post was successfully destroyed.' end private def post_params params.require(:post).permit(:title, :content) end def post @post ||= Post.find(params[:id]) end end
ビュー
<%= form_with(model: post_form) do |f| %> <% if post_form.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(post_form.errors.count, "error") %> prohibited this post_form from being saved:</h2> <ul> <% post_form.errors.each do |error| %> <li><%= error.full_message %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :title %> <%= f.text_field :title %> </div> <div class="field"> <%= f.label :content %> <%= f.text_area :content %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
スキーマ
ActiveRecord::Schema.define(version: 20_210_810_101_738) do create_table 'posts', force: :cascade do |t| t.string 'title' t.text 'content' t.datetime 'created_at', precision: 6, null: false t.datetime 'updated_at', precision: 6, null: false end end
参考
作成するにあたり、参考にさせていただいた記事。