How to merge value of child records into strong params in controller create action?

Viewed 37

In my Rails 7 app I have a client which can have a bunch of nested people:

class ClientsController < ApplicationController

  def new
    @client = Client.new
    @client.people.build
  end

  def create
    @client = current_account.clients.build(client_params.merge(:creator_id => current_user.id))
    if @client.save
      flash[:notice] = "Client created."
      redirect_to edit_client_url(@client)
    else
      @client.people.build unless @client.people.any?
      render :new
    end
  end

private

  def client_params
    safe_attributes = [
      :name,
      :people_attributes => Person::ATTRIBUTES + [:id, :_destroy]
    ]
    params.require(:client).permit(*safe_attributes)
  end

end

It turns out that we have to store the account_id with each person as well (each client belongs to an account already).

To achieve this I would like to merge current_account.id into each newly created person (as it's already done with the creator_id).

How can this be done?


One way of doing it would be in the Person model like this:

class Person < ApplicationRecord

  belongs_to :client
  belongs_to :account

  after_save :save_account_id

private

  def save_account_id
    update_column(:account_id, client.account.id) # does not feel right to me
  end

end

But this doesn't feel right to me since a Rails model (in my opinion) should be kept stupid and not know about e.g. its parent records (please correct me if I'm wrong).

I would prefer to do it in the controller. But how can it be done?

1 Answers

You could just add it into the merge you already have setup. Assuming you have access to client.account_id which I believe you would because you setup the belongs_to. If not you would have to do a DB query to get it but once you have it you could just add it into your existing merge. I have had to merge multiple params in other apps.

@client = current_account.clients.build(client_params.merge(
:creator_id => current_user.id,
:account_id => person.account_id
))
Related