Agazoom
Agazoom

Reputation: 618

Extra record showing in ActiveRecord query result

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

Answers (2)

daslicious
daslicious

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

SkyWriter
SkyWriter

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:

  1. 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>
    
  2. 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

Related Questions