Reputation: 1945
I have a fully working nested attributes form. But my problem is that when a validation fails the nested form fields are not shown after the render:
At first
After the validation fails, Location name
and Bin name
disappear:
In the model:
accepts_nested_attributes_for :location, reject_if: proc { |l| l[:name].blank? }
The partial _form.html.erb
<%= form_with(model: inventory_item, local: true) do |form| %>
<% if inventory_item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(inventory_item.errors.count, "error") %> prohibited this inventory_item from being saved:</h2>
<ul>
<% inventory_item.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form.fields_for :location do |location| %>
<div class="field">
<%= location.label :location_name %>
<%= location.text_field :name %>
</div>
<%= location.fields_for :bins do |bin| %>
<div class="field">
<%= bin.label :bin_name %>
<%= bin.text_field :name %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
The controller:
def new
@inventory_item = InventoryItem.new
@inventory_item.build_location.bins.build
end
def create
@inventory_item = InventoryItem.new(inventory_item_params)
respond_to do |format|
if @inventory_item.save
format.html { redirect_to @inventory_item, notice: "Inventory item was successfully created." }
format.json { render :show, status: :created, location: @inventory_item }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @inventory_item.errors, status: :unprocessable_entity }
end
end
end
def inventory_item_params
params.require(:inventory_item).permit(:location_id, :bin_id, location_attributes:[:name, bins_attributes:[:name]])
end
Thanks in advance
Upvotes: 0
Views: 836
Reputation: 6418
The issue is your @inventory_item
object which doesn't have the location
object associated. When the new action is called you build the location object like this:
@inventory_item.build_location.bins.build
So you will have to do something similar for the create action when there is an error. You could do something like this:
def new
@inventory_item = InventoryItem.new
build_location
end
def create
@inventory_item = InventoryItem.new(inventory_item_params)
respond_to do |format|
if @inventory_item.save
format.html { redirect_to @inventory_item, notice: "Inventory item was successfully created." }
format.json { render :show, status: :created, location: @inventory_item }
else
build_location #<----- call the method here and if the location doesn't exist then build a new object
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @inventory_item.errors, status: :unprocessable_entity }
end
end
end
def build_location
return if @inventory_item.location.present?
@inventory_item.build_location.bins.build
end
Upvotes: 2