使用 accepts_nested_attributes_for 将现有的 has_many 记录添加到新记录 [英] Adding existing has_many records to new record with accepts_nested_attributes_for

查看:19
本文介绍了使用 accepts_nested_attributes_for 将现有的 has_many 记录添加到新记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将现有的项目模型添加到新的付款模型时,会出现错误无法找到 ID=123 的项目以进行付款 ID=".这是一个 has_many 关系并使用 accepts_nested_attributes_for.

class Payment ActiveRecord::Basehas_many :项目accepts_nested_attributes_for :items...类项目

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

具体来说,错误发生在控制器的创建动作中:

# payment_controller.rb定义新@payment = Payment.new@payment.items = Item.available # where(payment_id: nil)结尾定义创建@payment = Payment.new payment_params # <-- 这里发生错误...结尾def payment_paramsparams.require(:payment).permit( ..., [items_attributes: [:id, :billcode]])结尾

lib/active_record/nested_attributes.rb:543:in 'raise_nested_attributes_record_not_found!' 在调用堆栈中紧跟在它之前.奇怪的是,ActiveRecord 将 Payment_id 作为搜索条件的一部分.

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

form_for @payment do |f|# 付款字段...fields_for :items 做 |i|# 项目字段

并且它在新操作上正确呈现项目.通过表单传递的参数如下所示:

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

如果有更好的方法来解决这个问题而不使用 accepts_nested_attributes_for 我愿意接受建议.

解决方案

这让我很困惑...

<块引用>

将现有记录添加到新记录..."

那么您有 Item 1, 2, 3,并希望将它们关联到一个新的 Product 对象?

--

加入模型

这样做的方法是使用 join 模型( 你的各种对象都有,还有一个偷偷摸摸的技巧,你可以使用 ItemsItems 添加到产品中代码>item_ids:

#app/controllers/products_controller.rb类 ProductsController <应用控制器定义创建@product = Product.new(product_params)@product.save结尾私人的def product_paramsparams.require(:product).permit(item_ids: [])结尾结尾

如果您随后将参数 item_ids[] 传递给您的 create_method,它将为您填充 collection.

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

#app/controllers/products_controller.rb类 ProductsController <应用控制器定义添加@product = Product.find params[:id]@item = Item.find params[:item_id]@product.items <<@物品@product.items.delete 参数[:item_id]结尾结尾

The error "Couldn't find Item with ID=123 for Payment with ID=" occurs when adding existing Item models to a new Payment model. This is in a has_many relationship and using accepts_nested_attributes_for.

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

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

The payment and item models are hypothetical but the problem is real. I need to associate the Items with the Payment (as I do in the new action) before saving the Payment (done in the create action). The user needs to modify attributes on the Items as they create the Payment (adding a billing code would be an example).

Specifically, the error occurs in the controller's create action:

# 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!' is immediately prior to it in the callstack. It is curious that ActiveRecord is including payment_id as part of the search criteria.

For the sake of being complete, the form looks something like this...

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

and it renders the Items correctly on the new action. The params passed through the form look like this:

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

If there is a better way to approach this that doesn't use accepts_nested_attributes_for I'm open to suggestions.

解决方案

This confused me...

"Adding existing records to a new record..."

So you have Item 1, 2, 3, and wish to associate them to a new Product object?

--

Join Model

The way to do this will be to use a join model (habtm) rather than sending the data through accepts_nested_attributes_for

The bottom line is every time you create a new Product object, its associated Item objects can only be associated to that product:

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

So if you're looking to use existing Item objects, how can you define multiple associations for them? The fact is you can't - you'll have to create an intermediary table / model, often cited as a join model:

#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

If you use a HABTM setup (as I have demonstrated above), it will allow you to add / delete from the collection your various objects have, as well as a sneaky trick where you can just add Items to a product using 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

If you then pass the param item_ids[] to your create_method, it will populate the collection for you.

If you want to add specific items to a product, or remove them, you may wish to do this:

#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

这篇关于使用 accepts_nested_attributes_for 将现有的 has_many 记录添加到新记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆