ruby-on-railsruby-on-rails-5rails-apiaccepts-nested-attributes

Unpermitted parameter in Rails API nested attributes


I'm trying to update an object using nested fields and am receiving an Unpermitted parameters error. The field that is causing the error is in itself a relation to another table within the nested table. Below are the specifics:

Doctor class

class Doctor < User
    has_many :professional_licenses, dependent: :destroy
    has_many :states, through: :professional_licenses
    accepts_nested_attributes_for :professional_licenses, allow_destroy: true
   ...
end

Professional License class

class ProfessionalLicense < ApplicationRecord
  belongs_to :doctor
  belongs_to :state

  validates_presence_of :code
end

State class

class State < ActiveRecord::Base
  validates_presence_of :iso_abbr, :name
end

Doctor controller

...
def update
  doctor = @current_user
  params[:doctor][:professional_licenses_attributes].each do |license, index|
    license[:state] = State.find_by_iso_abbr license[:state]
  end
  doctor.update_attributes(doctor_params)
  render json: doctor, status: :ok
end
...
def doctor_params
  params.require(:doctor).permit(:email, :first_name, :last_name, :password, 
  :password_confirmation, professional_licenses_attributes: [:code, :state, :_destroy])
end

The call from the UI looks like this:

{
"doctor":{
    "first_name":"Doctor Postman",
    "professional_licenses_attributes": [
        {
            "code": "NY-1234",
            "state": "NY"
        },
        {
            "code": "MA-1234",
            "state": "MA"
        }
    ]
}
}

When I send the call, the record is being updated and the licenses created. However, the licenses get created with no state because the controller says Unpermitted parameters: state. I have tried different approaches but can't find the way to permit the state. Please help!


Solution

  • In your case the code parameter is expected to be a simple value such as integer or string. But you convert it into an object, which attributes also have to be added to the permitted list.

    Try to pass code_id (integer) instead of code (object):

    ...
    def update
      doctor = @current_user
      params[:doctor][:professional_licenses_attributes].each do |license|
        state = State.find_by_iso_abbr(license.delete(:state))
        license[:state_id] = state.id if state
      end
      doctor.update_attributes(doctor_params)
      render json: doctor, status: :ok
    end
    ...
    def doctor_params
      params.require(:doctor).permit(:email, :first_name, :last_name, :password, 
      :password_confirmation, professional_licenses_attributes: [:code, :state_id, :_destroy])
    end