Reputation: 618
So here's the problem:
I have a page where I want a list of 'items' displayed. I also want to have a form on this page used for adding additional 'items'.
The 'new' action in the controller looks like this:
def new
@collection = current_user.collections.find_by_id(params[:collection_id])
@item_list = @collection.items
@item = @collection.items.new
end
The code in the view like this:
<div class="row-fluid">
<div id="main_area" class="col-sm-offset-3 col-sm-6 col-md-offset-4 col-md-4">
<div class="center">
<h3><%= @collection.title %></h3>
<% if @item_list.any? %>
<ul>
<% @item_list.each do |il| %>
<li>
<%=i l.name %>
<% end %>
</ul>
<% end %>
<div id="add_item">
<%=f orm_for [@collection, @item] do |f| %>
<div class="form-group <%= 'has-error has-feedback' if @item.errors[:name].present? %>">
<label class="sr-only" for="item_name">Item Name</label>
<%=f .text_field :name, :autofocus=>true, :placeholder => "Item Name", :class => "form-control", :'aria-describedBy' => "itemNameBlock" %>
<% if @collection.errors[:title].present? %>
<span id="itemNameBlock" class="error">Item <%= @item.errors[:name].first %></span>
<% end %>
</div>
<div id="signin_button_row">
<%=f .submit "Save", :class=>"form-control green_button" %>
<span id="forgot_my_password" class="right-justify">
<%= link_to "cancel", collection_items_path(@collection), :class => "new_colors terms" %>
</span>
</div>
<% end %>
</div>
</div>
</div>
</div>
My problem is the fact that the loop in the view always seems to have one extra 'item' in it, and this seems to be related to the fact that I'm using 'new' in the controller.
How do I get around this problem?
Upvotes: 1
Views: 66
Reputation: 1534
This will create the same item but not add it to the collection
def new
@collection = current_user.collections.find_by_id(params[:collection_id])
@item_list = @collection.items
@item = Item.new collection_id: @collection.id
end
Upvotes: 1
Reputation: 1479
The issue here is that when building a template Item object you're putting it to the collection as well, which is not what you want.
To me it looks like there are two possible fixes for this:
Do not display the new item by checking whether the item has been persisted or not when outputting a list:
<ul>
<% @item_list.reject(&:new?).each do |il| %>
<li>
<%= il.name %>
</li>
<% end %>
</ul>
Do not actually add the new template item to the collection, which makes more sense to me from the conceptual point of view, since you actually don't need that item to be associated with your items collection at the point of rendering the view, e.g.:
class ItemsController < ApplicationController
before_filter do
@collection = collection.find(params[:collection_id])
@items = @collection.items
end
def index
@item = Item.new
end
def create
@item = @items.new(item_params)
if @item.save
redirect_to collection_items_path
else
render action: :index
end
end
private
def item_params
params.require(:item).permit!
end
end
Hope that makes sense and works for you!
Upvotes: 1