Search code examples
ruby-on-railsnested-attributes

Rails 5 accepts_nested_attributes_for unpermitted parameter error? (React front end)


I have looked at previous SO solutions on accepts_nested_attributes here and here, but I am still getting the error. I am using React as front end and Rails back end. I am trying to create a request to be sent to schedules, and from there to populate to workers.

I am using Rails 5.0.2. I have a schedule, worker, roster models.

//Schedule
  has_many :workers, through: :rosters, dependent: :destroy
  has_many :rosters
  accepts_nested_attributes_for :workers #implement accept_nested_attributes here

//Roster
  belongs_to :schedule
  belongs_to :worker

//Worker
  has_many :schedules, through: :rosters
  has_many :rosters

And here is my Schedule controller:

  def create
    @schedule = Schedule.new(schedule_params)
    if @schedule.save
      render json: @schedule
    else
      render json: @schedule, status: :unprocessable_entity
    end
  end
  ...


private

  def schedule_params
    params.permit(:date, :user_id, :workers_attributes => [:worker_id, :name, :phone])
  end

Here is the error that I got:

app/controllers/schedules_controller.rb:13:in `create'
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 10:30:38 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>{"name"=>"Iggy Test", "phone"=>"1
23-456-7890"}, "schedule"=>{"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
Completed 500 Internal Server Error in 15ms (ActiveRecord: 0.0ms)



TypeError (no implicit conversion of Symbol into Integer):

app/controllers/schedules_controller.rb:13:in `create'

Why is my request shows Unpermitted parameter schedule? If I remove workers_attributes and only have params.permit(:date, :user_id), it works. I can't figure out why the error points to schedule. How can I make successful POST nested_attributes request to rails?

I am using fetch to do POST request from react side:

...
return fetch(`api/schedules`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      date: date,
      user_id: 1,
      workers_attributes: {name: "Iggy Test", phone: "123-456-7890"}
    })

EDIT:

After following answer from @gabrielhilal, I added require(): params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone]), and edited the fetch POST on React's end to have array of objects instead of plain objects: workers_attributes: [{name: "Iggy Test", phone: "123-456-7890"}]. It does not complain anymore, and it does register new schedule. However, new workers are all nil:

#Worker.last shows:
 #<Worker id: 32, name: nil, phone: nil, created_at: "2017-05-23 19:36:09", updated_at: "2017-05-23 19:36:09">

Sorry, don't mean to create nested question, but does anyone know why it is nil?

EDIT 2:

I got it to work, sort of.

If I have

def create
    @schedule = Schedule.new(schedule_params)
    @workers = @schedule.rosters.build.build_worker
...

and

//schedule_params
params.permit(:date, :user_id, :workers_attributes => [:id, :name, :pho

ne])

I was able to have "Iggy Test" to display, but it immediately creates another nil worker.

Log:

Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:42:38 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
   (0.1ms)  begin transaction
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (1.1ms)  INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC], ["user_id", 1]
]
  SQL (0.2ms)  INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "Iggy
Test"], ["phone", "123-456-7890"], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
  SQL (0.2ms)  INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["worker_id", 56], ["c
reated_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]

  SQL (0.1ms)  INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2017-05-24 03:42:38 UTC
], ["updated_at", 2017-05-24 03:42:38 UTC]]
  SQL (0.6ms)  INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sc
hedule_id", 52], ["worker_id", 57], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
  SQL (0.4ms)  UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ?  [["schedule_id", 52],
["updated_at", 2017-05-24 03:42:38 UTC], ["id", 52]]
   (5.6ms)  commit transaction
Completed 200 OK in 417ms (Views: 6.9ms | ActiveRecord: 14.7ms)

If I modified params to have require(:schedule)

params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])

It creates a nil worker only.

Log:

Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:45:03 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
   (0.1ms)  begin transaction
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.4ms)  INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC], ["user_id", 1]
]
  SQL (0.2ms)  INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2017-05-24 03:45:03 UTC
], ["updated_at", 2017-05-24 03:45:03 UTC]]

  SQL (0.3ms)  INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sc
hedule_id", 53], ["worker_id", 58], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC]]
   (2.4ms)  commit transaction
Completed 200 OK in 81ms (Views: 1.3ms | ActiveRecord: 8.3ms)

Solution

  • Your post:

    {
      "date"=>"2017-05-25T02:00:00.000Z",
      "user_id"=>1,
      "workers_attributes"=>{
        "name"=>"Iggy Test",
        "phone"=>"123-456-7890"
      },
      "schedule"=> {
        "date"=>"2017-05-25T02:00:00.000Z",
        "user_id"=>1
      }
    }
    

    You have two issues:

    • schedule is not permitted (that's why you see the message in the logs), but it will be just ignored anyway (won't raise any error).
    • the workers_attributes should be a collection of workers and not a simple hash, so that's why you are having the error.

    You should get something like the following in the post request:

    {
      "date"=>"2017-05-25T02:00:00.000Z",
      "user_id"=>1,
      "workers_attributes"=>{
        "0" => {
          "name"=>"Iggy Test",
          "phone"=>"123-456-7890"
        }
      }
    }