使用accepts_nested_attributes_for将现有has_many记录添加到新记录

时间:2014-06-06 20:19:41

标签: ruby-on-rails activerecord ruby-on-rails-4

错误"找不到ID = 123的物品,ID ="将现有项模型添加到新的付款模型时发生。这是一个has_many关系并使用accepts_nested_attributes_for。

class Payment < ActiveRecord::Base
  has_many :items
  accepts_nested_attributes_for :items
  ...

class Item < ActiveRecord::Base
  belongs_to :payment
  ...

付款和项目模型是假设的,但问题是真实的。在保存付款(在创建操作中完成)之前,我需要将项目与付款关联(就像我在新操作中一样)。用户需要在创建付款时修改项目的属性(添加帐单代码就是一个例子)。

具体而言,错误发生在控制器的创建操作中:

# payments_controller.rb

def new
  @payment = Payment.new
  @payment.items = Item.available # where(payment_id: nil)
end

def create
  @payment = Payment.new payment_params # <-- error happens here
  ...
end

def payment_params
  params.require(:payment).permit( ..., [items_attributes: [:id, :billcode]])
end

lib/active_record/nested_attributes.rb:543:in 'raise_nested_attributes_record_not_found!'紧接在callstack之前。很遗憾ActiveRecord将payment_id作为搜索条件的一部分。

为了完整,表格看起来像这样...

form_for @payment do |f|
   # payment fields ...
   fields_for :items do |i|
     # item fields    

并在新操作上正确呈现Items。通过表单的params看起来像这样:

{ "utf8"=>"✓",
  "authenticity_token"=>"...",
  "payment"=>{
    "items_attributes"=>{
      "0"=>{"billcode"=>"123", "id"=>"192"}
    },
  }
}

如果有更好的方法可以使用accepts_nested_attributes_for,我可以接受建议。

2 个答案:

答案 0 :(得分:13)

我通过向params添加item_ids集合(除items_attributes之外)来实现此目的。你应该能够在控制器中按下你的参数看起来像这样

{ "utf8"=>"✓",
  "authenticity_token"=>"...",
  "payment"=>{
    "item_ids"=>[192]
    "items_attributes"=>{
      "0"=>{"billcode"=>"123", "id"=>"192"}
    },
  }
}

更新1:出于某种原因,只有当item_ids在哈希值items_attributes之前时才会有效。尚未审核Rails docs尚未找出原因。

答案 1 :(得分:1)

这让我很困惑......

  

“将现有记录添加到新记录中......”

所以你有Item 1, 2, 3,并希望将它们与新的Product对象相关联?

-

加入模型

执行此操作的方法是使用join modelhabtm),而不是通过accepts_nested_attributes_for

发送数据

底线是每次创建新的Product对象时,其关联的Item对象只能 与该产品相关联:

#items table
id | product_id | information | about | item | created_at | updated_at

因此,如果您要使用existing Item个对象,如何为它们定义多个关联?事实是你不能 - 你必须创建一个中间表/模型,通常被引用为join model

enter image description here

#app/models/product.rb
Class Product < ActiveRecord::Base
   has_and_belongs_to_many :items
end

#app/models/item.rb
Class Item < ActiveRecord::Base
   has_and_belongs_to_many :products
end

#items_products (table)
item_id | product_id

-

<强> HABTM

如果您使用HABTM设置(如上所述),它将允许您从各种对象的collection添加/删除,以及一个偷偷摸摸的技巧,您只需添加{{ 1}}使用Items生成产品:

item_ids

如果您将参数#app/controllers/products_controller.rb Class ProductsController < ApplicationController def create @product = Product.new(product_params) @product.save end private def product_params params.require(:product).permit(item_ids: []) end end 传递给item_ids[],则会为您填充create_method

如果您要将特定商品添加到collection或删除它们,您可能希望这样做:

product