Strong Parameters Nested of Nested (has_many => has_one)

Hi guys,

I have problem of figuring out how to set my strong parameters in a controller.

Right now, pretty simple, I have a User model that has many employees

class User < ApplicationRecord
  has_many :employees
end

class Employee < ApplicationRecord
  belongs_to :user
end

When I create a user in my controller, I tell that I permit employee ids to add ALREADY created employees to user

class UsersController < ApplicationController
  # only showing what's going on with params
  # also, employees are already created in database, so I just need to associate Ids
  def user_params
    params.permit(:employee_ids => [])
  end
end

now I can post something like this

{
  employee_ids: [5]
}

It works very well. If employee ID 5 exists and I want to create a User having that employee in its has_many association, it will work pretty well.

But now I added a new association to Employee model.

class Employee < ApplicationRecord
  belongs_to :user
  has_one :agreement # new association that is empty
end

So this is where I have a problem. How can I tell my UserController to accept employee_ids AND create a new Agreement at the same time for a specific employee?

For example, this doesn’t work but let’s say I want something like this

class UsersController < ApplicationController
  def user_params
    params.permit(:employee_ids => [:agreements_attributes])
  end
end

so that I can post something like that

{
  employee: {
    id: 5,
    agreement: {
      confirmed_at: "some new date here"
    }
  }
}

So in one action, how can I associate the already employee to the has_many user but ALSO create an agreement to the associated employee?

Thanks

The “Rails Way” to do this is to add accepts_nested_attributes_for on your two models, and then create an appropriate params hash which is nested. There is a slick way to make all of this pretty easy – use The Brick! I’ve replicated your environment in one of my projects and made a quick video which shows how you can determine the appropriate nested set of params:

The resulting params hash that is seen in the video is this:

  def user_params
    params.require(:user)
          .permit(:id, :name, :type, :public_id, :job_id, :level, :manager_id, :blurb, :url,
                  {:employees_attributes=>[:id, :user_id, :firm,
                                           {:agreement_attributes=>[:id, :employee_id, :name, :_destroy]},
                                           :_destroy
                                          ]
                  }
                 )
  end
1 Like

Wow, not only you fixed my problem, but I also learn a new gem that is quite useful. Also, thanks for having time to create a video for this, I mean, it’s not always that someone takes time to fully explain something and freely.

I really appreciate it!

1 Like

Glad it worked out!

This gem is one I maintain, and putting together this sample allowed me to carefully test out how this param nesting works. Along the way I found a bug in my code, and was able to implement a fix, so everything ended up win-win on all fronts!

1 Like