LoginSignup
9
3

More than 3 years have passed since last update.

[Ruby on Rails] date_selectで分割されたパラメーターをFormObjectに渡す。

Last updated at Posted at 2020-07-12

一つのフォームの送信で複数のモデルを更新したいときなど、FormObjectを利用するかと思います。
(FormObjectについて知りたい方はこちら:【Rails】FormObjectを使ってほしい

その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>を取得。

app/controllers/users_controller.rb
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
app/forms/form.rb
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パラメーターとして渡したい。
image.png

そこで、include ActiveRecord::AttributeAssignmentを宣言すると、分割されたパラメーターをまとめてattributeに渡してくれる。一件落着。

app/forms/form.rb
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

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