accept_nested_attributes_for在Rails上创建一个额外的nil记录

时间:2017-05-24 17:18:02

标签: ruby-on-rails nested-attributes

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

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

My 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。当我在schedule_params中添加require(:schedule)时,该消息消失了,但它只会创建一个零工作者。

1 个答案:

答案 0 :(得分:0)

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

“未经许可的参数:schedule”只是警告,在.permit中没有列入白名单的参数哈希中存在参数。它被记录,因为它可能是一个恶意的尝试捕获大规模分配漏洞。

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

相反,你应该调查为什么反应发送的参数包括两个未包装的参数,我不明白你为什么要发送未包装的参数和"schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1}哈希。我真的不知道React,但我猜它与this.state.schedules.concat([schedule])

有关