1

我正在尝试构建一个允许用户更新一些记录的表单。但是,它们无法更新每个字段,因此我将进行一些显式处理(目前在控制器中)以更新模型相对于表单。这是我正在尝试的方法:

家庭型号:

class Family < ActiveRecord::Base
  has_many :people, dependent: :destroy
  accepts_nested_attributes_for :people, allow_destroy: true, reject_if: ->(p){p[:name].blank?}
end

在控制器中

def check
  edited_family = Family.new(params[:family])
  #compare to the one we have in the db
  #update each person as needed/allowed
  #save it
end

形式:

= form_for current_family, url: check_rsvp_path, method: :post do |f|
  = f.fields_for :people do |person_fields|
    - if person_fields.object.user_editable
      = person_fields.text_field :name, class: "person-label"
    - else
      %p.person-label= person_fields.object.name

我想,问题是Family.new(params[:family])试图将人们从数据库中拉出来,我得到了这个:

ActiveRecord::RecordNotFound in RsvpsController#check

Couldn't find Person with ID=7 for Family with ID=

那是,我猜,因为我没有在嵌套表单中添加家庭 id 字段,我想我可以这样做,但我实际上并不需要它从数据库中加载任何内容,所以我会而不是。我也可以通过自己挖掘参数哈希来获取我需要的数据来解决这个问题,但这并不容易。从 params 哈希中创建一个对象然后使用它似乎最好。

有没有更好的办法?我怎样才能创建嵌套对象?

4

2 回答 2

1

我建议不要使用这些参数实例化一个新的 Family 对象,而是为 check rsvp 操作创建一个成员路由。该路线将采用以下形式:

resources :families do
  member do
    post 'check_rsvp'
  end
end

form_for 将自动传递 current_family 的 id,因此检查操作将如下所示:

def check
  edited_family = Family.find(params[:id])
  # ...
end

虽然这在功能上似乎等同于自己添加家庭 id 参数,但我认为它优于或者基于其他参数实例化一个新的家庭对象,因为:

  1. 它更加地道(The Rails Way™)。
  2. 它的代码更少。
  3. 您获得了edited_family 对象的引用透明度,这减少了由于基于已持久化的属性的新Active Record 对象的临时实例化而可能发生的细微错误的可能性。
于 2012-12-01T20:03:43.703 回答
0

我最终接受了@244an 的建议:

class Person < ActiveRecord::Base
  belongs_to :family

  def temp_id
    @temp_id || self.id
  end

  def temp_id=(new_id)
    @temp_id = new_id
  end
end

在表格中:

= form_for current_family, url: check_rsvp_path, method: :post, html: {class: "form-inline"} do |f|
  #people-list
    = f.fields_for :people, include_id: false do |person_fields|
      = person_fields.hidden_field :temp_id
      #rest of the form here

然后在我的控制器中:

def check
    @edited_family = Family.new(params[:family])

    current_people = Hash[current_family.people.map{|p| [p.id, p]}]

    @edited_family.people.each do |person|
      current_person = current_people[person.temp_id.to_i]

      next unless current_person

      current_person.name = person.name if current_person.user_editable
      current_person.attending = person.attending
      current_person.save!
    end

    current_family.responded = true
    current_family.save!

  end

我将该字段添加到模型中的原因是我想不出一个好的方法hidden_field来重命名该字段。

无论如何,它感觉超级哈克,但它有效。我真正想要的只是一种告诉new不要尝试将子对象与数据库匹配的方法,即使它们有 id。

于 2012-12-04T00:59:04.673 回答