[Ruby] [Ruby on Rails] Pass parameters separated by date_select to FormObject.

2 minute read

If you want to update multiple models with one form submission, you should use FormObject. (If you want to know about FormObject, click here: [Rails] Use FormObject)

I was troubled because I could not pass the parameters divided by date_select to the FormObject as it was, but when I declared include ActiveRecord::AttributeAssignment in the FormObject, I could pass them all together, so I would like to introduce it below. I will.

Explanation

The situation is when you register your birthday on the new registration screen.

When you press the Create User button on the image, the controller’s create action runs. Split parameters using the StrongParameter mechanism in the user_params method <ActionController::Parameters {"birthday(1i)"=>"2020", "birthday(2i)"=>"7", "birthday(3i) Acquired "=>"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

As described in @user = Form.new(user_params), When I try to pass a divided parameter with the initial value of FormObject, an error occurs because it is divided. Summary of <ActionController::Parameters {"birthday(1i)"=>"2020", "birthday(2i)"=>"7", "birthday(3i)"=>"12"} permitted: true> I want to pass it as a birthday parameter. image.png

So, if you declare include ActiveRecord::AttributeAssignment, it will pass the divided parameters together to attribute. case being settled.

app/forms/form.rb


class Form
  include ActiveModel::Model
  include ActiveModel::Attributes
  # add to
  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