0

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!

  • Could you inspect your `params` before and after `.each` cycle? – Pavel Mikhailyuk Jun 16 '17 at 15:34
  • Which _unpermitted param_? Please show complete error/log. – Gerry Jun 16 '17 at 16:01
  • @Gerry the error I get is `{"message":"undefined method `iso_abbr' for nil:NilClass"}`. the `iso_abbrr` is the State's abbreviation in that table. Here's the console output too https://gist.github.com/davidflores2/2818385e1f217456d6a2bac40e4b00d5 – David Flores Jun 19 '17 at 11:15
  • @PavelMikhailyuk here are the params before and after: https://gist.github.com/davidflores2/6e5f73612b43a5df4e724fcc4927bd32 – David Flores Jun 19 '17 at 11:16

1 Answers1

1

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
chumakoff
  • 6,807
  • 2
  • 23
  • 45
  • Thanks for the response. In this case, `:code` is a string so I can't pass the id. I have tried to pass just `:state` and the object and I also get the same error as when I do `:state_id` – David Flores Jun 19 '17 at 11:02
  • You don't have to pass ID. You pass a string and calculate the ID, based on the string. You also should remove `:state` from `params` after you convert it to `state_id` (I missed this when answered). I updated the answer. Now `:state` is removed from `params` after it is converted into `state_id` – chumakoff Jun 19 '17 at 11:16
  • I made the change you suggested and get the same error: `"undefined method 'iso_abbr' for nil:NilClass"` Here's a gist with the console output. Maybe you can see something I'm not. https://gist.github.com/davidflores2/ca334be415526fd1c03e874d973980c9 – David Flores Jun 19 '17 at 15:46
  • In the gist the code is wrong! You missed `license.delete(:state)` and `if state` Copy it from here and use properly. – chumakoff Jun 19 '17 at 16:12