一つのフォームの送信で複数のモデルを更新したいときなど、FormObjectを利用するかと思います。
(FormObjectについて知りたい方はこちら:[【Rails】FormObjectを使ってほしい] (https://qiita.com/9ro/items/10e3676741e09ffb98bb ))
そのFormObjectにdate_select
で分割されたパラメーターをそのまま渡すことできなく困っていた矢先、FormObjectにinclude ActiveRecord::AttributeAssignment
を宣言したら、まとめて渡すことができたので以下にて紹介したいと思います。
説明
画像のCreateUser
ボタンを押すと、コントローラーのcreateアクションが走ります。user_paramsメソッドでStrongParameterの仕組みを使って、分割されたパラメーター<ActionController::Parameters {"birthday(1i)"=>"2020", "birthday(2i)"=>"7", "birthday(3i)"=>"13"} permitted: true>
を取得。
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
@users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = Form.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
@user = Form.new(user_params)
respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
else
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Only allow a list of trusted parameters through.
def user_params
params.require(:user).permit(:birthday)
end
end
class Form
include ActiveModel::Model
include ActiveModel::Attributes
attribute :birthday, :date
def to_model
User.new(birthday: birthday)
end
def save
return false if invalid?
to_model.save
end
end
@user = Form.new(user_params)
で記載されているように、
分割されたパラメーターをFormObjectの初期値で渡そうと思うと、分割されているが故にエラーが起きてしまう。<ActionController::Parameters {"birthday(1i)"=>"2020", "birthday(2i)"=>"7", "birthday(3i)"=>"12"} permitted: true>
をまとめてbirthdayパラメーターとして渡したい。
そこで、include ActiveRecord::AttributeAssignment
を宣言すると、分割されたパラメーターをまとめてattributeに渡してくれる。一件落着。
class Form
include ActiveModel::Model
include ActiveModel::Attributes
# 追加
include ActiveRecord::AttributeAssignment
attribute :birthday, :date
def to_model
User.new(birthday: birthday)
end
def save
return false if invalid?
to_model.save
end
end