Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
884 views
in Technique[技术] by (71.8m points)

ruby on rails - Adding existing has_many records to new record with accepts_nested_attributes_for

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I got this to work by just adding an item_ids collection to the params (in addition to the items_attributes). You should just be able to massage your parameters in the controller to look like this

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

UPDATE 1: For some reason this only works if item_ids is before items_attributes in the hash. Have not reviewed Rails docs yet to figure out why.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...