I am essentially running into the same issue as this post, though I have a slightly different situation: has_many nested form with a has_one nested form within it
But as someone else mentioned in that post, the provided answer does not solve the issue.
The relationship is set up so that Invoice has_many items and each Item has_one Modifier. I am attempting to make a single form_for Invoice that allows a use to create many items, each with a Modifier.
MODELS
class Invoice < ActiveRecord::Base
has_many :items
has_many :modifiers, through: :items
accepts_nested_attributes_for :items
end
class Item < ActiveRecord::Base
belongs_to :invoice
belongs_to :modifier
accepts_nested_attributes_for :modifier
end
class Modifier < ActiveRecord::Base
has_one :item
end
CONTROLLER
class Invoice
def new
@invoice = Invoice.new
end
def edit
end
...
end
VIEWS(haml)
invoice.html.haml:
= form_for @invoice do |f|
= f.text_field :status
= f.fields_for :items do |builder|
= render partial: "items/fields", locals: { :f => builder }
= link_to_add_association 'New Item', f, :items, partial: "items/fields", id: "add-item-button"
items/_fields.html.haml:
.nested-fields
- @item = @invoice.items.build
= f.fields_for :modifier, @item.build_modifier do |modifier|
= modifier.text_field :name
Let's review what's happening. In order to build the nested has_one relationship, I build an Item in the nested-fields partial so that I can build the has_one Modifier. This is because rails requires that you explicitly call 'build_something' in a has_one relationship (usually this is called in the controller's new, but I only want to build once someone has clicked the New Item button). For creating new Invoices, this code works perfectly. Checking console, I see that the relationship is created and I can verify that the Modifier was created successfully.
However, when I go back to edit the invoice, cocoon knows that I already have a modifier, so it calls the partial once to create the necessary fields_for my single Modifier. These fields are empty. This makes sense though, because as cocoon is rendering that partial, it is building a new Code with a new modifier and setting the fields blank. I can confirm that is what is occuring because once I have my modifier saved properly, I can go into my partial, remove the two build calls, and view the edit page which properly displays the saved Modifier info just fine.
Of course, now that I've removed my build calls, the form no longer saves any Modifiers that I create. So essentially, I need the build calls in there to build new Modifiers, but I can't have them in there if I want to view them.
Does anyone have a solution to this situation? I have found multiple stack overflow questions and none of them resolves this issue.
You say has_one
but in your model I see has_many
?
You nested partial items/_fields
is wrong: you build an extra item and there is not need for that. Coccon, in the link_to_add_association
builds a new item to insert.
There are two ways to do what you want to do.
1) In the partial
To handle it correctly in your partial you can do the following (items/_fields.html.haml
) :
.nested-fields
- f.object.build_modifier if f.object.new_record?
= f.fields_for :modifier do |modifier|
= modifier.text_field :name
In rails, to refer to the object of the form you can use f.object
. Note this will work, but we have to check if it is a newly created object. Alternatively we could just check if the modifier
is present.
2) Using the :wrap_object
option ( documentation )
Cocoon allows to execute some extra code with the newly created object. So in your case that would become:
= link_to_add_association('New item', f, :items,
:wrap_object => Proc.new { |item| item.build_modifier; item })