accept_nested_attributes_for 在 Rails 上创建了一条额外的零记录

accept_nested_attributes_for creates one extra nil record on Rails

我使用 Rails 作为后端,使用 React 作为前端。在 React 方面,我正在使用 fetch 对名为 schedule 的模型执行 POST 请求。我还为 worker 模型添加了一个子属性。

这是我的一些代码片段。我在 rails 中使用 has_many :through 关系。

我的 Rails 型号和控制器:

//schedule.rb
  has_many :workers, through: :rosters, dependent: :destroy
  has_many :rosters, inverse_of: :schedule

//worker.rb
  has_many :schedules, through: :rosters
  has_many :rosters, inverse_of: :worker

//roster.rb
  belongs_to :schedule
  belongs_to :worker

//schedules_controller.rb
def create
    @schedule = Schedule.new(schedule_params)
    @workers = @schedule.rosters.build.build_worker
    if @schedule.save
      render json: @schedule
    else
      render json: @schedule, status: :unprocessable_entity
    end
  end 
  ...
  def schedule_params
    params.permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])
  end

在 React 方面:

//inside Client.js
function postSchedule(date, cb) {
  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"}, {name: "Iggy Test 2", phone: "987-654-3210"}]
    })
  }).then((response) => response.json())
    .then(cb);
};



//inside main app:
  postSchedule(){
      Client.postSchedule(this.state.date, (schedule) => {
        this.setState({schedules: this.state.schedules.concat([schedule])})
      })
  };

我遇到的问题是,当我提交新的时间表时,我希望看到一个有两个工人的新时间表:"Iggy Test" 和 "Iggy Test 2"。但是,当我查看 Rails 内部时,它正在创建 3 个工人:"Iggy Test""Iggy Test 2"nil

这是我提交请求时发生的情况:

Started POST "/api/schedules" for 127.0.0.1 at 2017-05-24 09:55:16 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}, {"name"=>"Iggy Test 2", "phone"=>"987-654-3210"}], "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "use
r_id"=>1}}
Unpermitted parameter: schedule
   (0.1ms)  begin transaction
  User Load (0.4ms)  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-27 02:00:00 UTC], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 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 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]

  SQL (0.2ms)  INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["worker_id", 64], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
  SQL (0.1ms)  INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "Iggy
Test 2"], ["phone", "987-654-3210"], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
  SQL (0.1ms)  INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["worker_id", 65], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
  SQL (0.2ms)  INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2017-05-24 16:55:16 UTC
], ["updated_at", 2017-05-24 16:55:16 UTC]]
  SQL (0.2ms)  INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sc
hedule_id", 57], ["worker_id", 66], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
  SQL (0.7ms)  UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ?  [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 60]]
  SQL (0.1ms)  UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ?  [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 61]]
   (2.6ms)  commit transaction
Completed 200 OK in 68ms (Views: 0.8ms | ActiveRecord: 5.6ms)

日志创建了一个时间表,然后是一个工人(Iggy 测试),然后是一个花名册(用于该时间表和 Iggy 测试),然后是另一个工人(Iggy 测试 2),然后是另一个花名册(用于 Iggy 测试 2 和那个) schedule) - 它没有停止,而是创建了另一个 worker (nil) 和那个 nil worker 的名册。

为什么会这样?我如何修复它以仅创建指定的工人?

附带说明 - 如果您注意到,日志会显示不允许的参数:计划。当我在我的 schedule_params 中添加 require(:schedule) 时,该消息消失了,但它只会创建一个 nil worker。

accepts_nested_attributes_for 没有创建额外的记录。你是。

def create
  @schedule = Schedule.new(schedule_params)
  # This adds a worker with no attributes
  @workers = @schedule.rosters.build.build_worker
  if @schedule.save
    render json: @schedule
  else
    render json: @schedule, status: :unprocessable_entity
  end
end

"Unpermitted parameter: schedule" 只是一个警告,表明参数散列中有一个参数未被 .permit 列入白名单。它被记录下来,因为它可能是恶意尝试寻找质量分配漏洞。

.require 从 params 散列中获取一个键,如果它不存在并且当你有一个平面 params 散列时不是你想要的,则会引发错误。

相反,您应该研究为什么 React 发送的参数包括未包装的参数,我不明白您为什么要同时发送未包装的参数和 "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1} 哈希。我不太了解 React,但我猜它与 this.state.schedules.concat([schedule])

有关