I have been troubleshooting this error for hours and I have no idea what I’m doing wrong. I simply can’t get the items collection to properly display for an individual user. Each item belongs to a single user and each user has many items. Right now, my partial is not rendering on the users show view.
If I change <%= render partial: "/users/item", collection: @user.items %>
to <%= render partial: "/users/item", collection: @items %>
then the partial template is rendered, but all items are displayed regardless of which user they belong to. After checking the database, each item entry is being properly stored with a foreign key user_id, so that isn’t the issue.
How do I get the correct items to display for each user? I have used partials several times before and I’ve cross-referenced old and new code. I can’t see the difference and I’m losing my mind. I’ve searched the general internets, Stack Overflow, and reviewed the Rails Guides for Layouts and Rendering. I've posted the relevant code below and happy to post anything else. Please help!
views/users/_item.html.erb
<div>
<h4>ITEM: <%= item.title %></h4>
<p class="item"><%= item.cost %></p>
</div>
views/users/show.html.erb
<h1>Users#show</h1>
<p>Find me in app/views/users/show.html.erb</p>
<div><%= @user.first_name %></div>
<h3>My List</h3>
<%= render partial: "/users/item", collection: @user.items %>
<span>ADD ITEM <%= link_to image_tag("Plus-50.png"), new_user_item_path(@user), class: "items-nved" %> </span>
controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
@users = User.all
render :index
end
def show
@user = User.find(params[:id])
# @item = Item.find(params[:id])
@items = Item.all
@item = Item.new
@item.user_id = @user.id
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to new_session_path, method: :get
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:first_name, :last_name, :birthday, :city, :state, :email, :password, :password_confirmation)
end
end
controllers/items_controller.rb
class ItemsController < ApplicationController
include ItemsHelper
before_filter :require_login, only: [:new, :create, :update, :destroy]
def index
@current_user = current_user
@items = Item.all
end
def show
@user = current_user
@item = Item.find(params[:id])
end
def new
@user = current_user
@item = Item.new
end
def create
@user = current_user
@item = Item.new(item_params)
@item.user_id = params[:user_id] # set user_id param from database to current_user id
@item.save
redirect_to user_item_path(@user, @item)
end
def edit
@user = current_user
@item = Item.find(params[:id])
end
def update
@user = current_user
@item = Item.find(params[:id])
@item.update(item_params)
redirect_to user_path(@user)
end
def destroy
@user = User.find params[:user_id]
@item = Item.find(params[:id])
@item.destroy
redirect_to user_path(@user)
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :birthday, :city, :state, :email, :password, :password_confirmation)
end
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
Install the byebug gem, either by running gem install byebug
on your command line or by putting byebug in your Gemfile (then run bundle install
).
Put byebug
just after the @user declaration in your UsersController, like this:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
@users = User.all
render :index
end
def show
@user = User.find(params[:id])
byebug
Then start your local server and go the user show view in your browser. The page won't render, because when it hits byebug
the server pauses.
When this happens, go back to your Terminal and look at your server log. It will be waiting for your commands. Type @user
and press Enter. What does it return?
Also try @user.inspect
. Does it return a User object?
Then do @user.items
. What does that return? If @user.items
returns the expected collection of items, then there is something wrong with how you are passing that to the view, or what you're doing with it in the view.
If @user.items
doesn't return a collection of items, then that's why it isn't showing in your view! In this case, it's probably something to do with your ActiveRecord associations and/or your migrations.
Another possibility is that the current Items in your database may have been created before you had the associations setup, so they won't have a user_id. You can check this in your rails console. Make sure you have Items in your database that have the same user_id as your current_user.
Another good thing to do in your rails console would be to assign a User, that you think has some Items, to a variable eg user = User.first
, and then do user.items
. Does that work?
I also recommend writing some RSpec tests, at least at Model level to test that the proper associations exist. The shoulda gem is great for this.
Comment here with your findings.