ruby-on-rails – 使用accepts_nested_attributes_for将现有的has_many记录添加到新记录中

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 使用accepts_nested_attributes_for将现有的has_many记录添加到新记录中前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
将现有项模型添加到新的付款模型时,会出现错误“无法找到ID = 123的项目,ID = 123”.这是一个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:在’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我会接受建议.

解决方法

这困惑了我……

“Adding existing records to a new record…”

那么你有第1,2,3项,并希望将它们与一个新的Product对象相关联?

加入模型

这样做的方法是使用连接模型(habtm)而不是通过accepts_nested_attributes_for发送数据

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

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

因此,如果您要使用现有的Item对象,如何为它们定义多个关联?事实是你不能 – 你必须创建一个中间表/模型,通常被称为连接模型:

#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添加/删除您的各种对象,以及一个偷偷摸摸的技巧,您可以使用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

如果您随后将param item_ids []传递给create_method,它将为您填充集合.

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

#app/controllers/products_controller.rb
Class ProductsController < ApplicationController
   def add
     @product = Product.find params[:id]
     @item = Item.find params[:item_id]

     @product.items << @item
     @product.items.delete params[:item_id]
   end
end

猜你在找的Ruby相关文章