My destroy unit test for line_item model is failing with the error "Couldn't find Product with id=1". It seems that Rails can't destroy my line_item because it throws an exception when getting it from the database. Here is my LineItem model:
class LineItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart
def total_price
product.price * quantity
end
end
And here is the test suite:
require 'test_helper'
class LineItemsControllerTest < ActionController::TestCase
setup do
@line_item = line_items(:one)
Rails.logger.debug(@line_item.to_yaml)
Rails.logger.debug(Product.all.to_yaml)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:line_items)
end
test "should get new" do
get :new
assert_response :success
end
test "should create line_item" do
assert_difference('LineItem.count') do
post :create, product_id: products(:ruby).id
end
assert_redirected_to cart_path(assigns(:line_item).cart)
end
test "should show line_item" do
get :show, id: @line_item
assert_response :success
end
test "should get edit" do
get :edit, id: @line_item
assert_response :success
end
test "should update line_item" do
put :update, id: @line_item, line_item: @line_item.attributes
assert_redirected_to line_item_path(assigns(:line_item))
end
test "should destroy line_item" do
Rails.logger.debug "Breaking!"
assert_difference('LineItem.count', -1) do
delete :destroy, id: @line_item
end
assert_redirected_to cart_path(path)
end
end
And here is the part that I have logged:
Breaking!
[1m[35m (0.1ms)[0m SELECT COUNT(*) FROM "line_items"
Processing by LineItemsController#destroy as HTML
Parameters: {"id"=>"980190962"}
[1m[36mLineItem Load (0.1ms)[0m [1mSELECT "line_items".* FROM "line_items" WHERE "line_items"."id" = ? LIMIT 1[0m [["id", "980190962"]]
[1m[35mProduct Load (0.1ms)[0m SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 1]]
Completed 500 Internal Server Error in 3ms
[1m[36m (0.1ms)[0m [1mrollback transaction[0m
[1m[35m (0.1ms)[0m begin transaction
[1m[36mLineItem Load (0.1ms)[0m [1mSELECT "line_items".* FROM "line_items" WHERE "line_items"."id" = ? LIMIT 1[0m [["id", 980190962]]
--- !ruby/object:LineItem
attributes:
id: 980190962
product_id: 1
cart_id: 1
created_at: 2012-05-25 20:37:17.000000000 Z
updated_at: 2012-05-25 20:37:17.000000000 Z
quantity: 1
product_price:
[1m[35mProduct Load (0.2ms)[0m SELECT "products".* FROM "products"
---
- !ruby/object:Product
attributes:
id: 207281424
title: Programming Ruby 1.9
description: Ruby is the fastest growing and most exciting dynamic language out
there. If you need to get working programs delivered fast, you should add Ruby
to your toolbox.
image_url: ruby.png
price: 49.5
created_at: 2012-05-25 20:37:17.000000000 Z
updated_at: 2012-05-25 20:37:17.000000000 Z
EDIT: here is the Product model:
class Product < ActiveRecord::Base
has_many :line_items
before_destroy :ensure_not_referenced_by_any_line_item
# Validation
validates :title, :description, :image_url, presence: true
validates :title, length: {
minimum: 10,
message: "must be at least %{count} characters long"
}
validates :price, numericality: { greater_than_or_equal_to: 0.01 }
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)$}i,
message: 'must be a URL for GIF, JPG or PNG image.'
}
private
def ensure_not_referenced_by_any_line_item
if line_items.empty?
return true
else
errors.add :base, 'Line items present'
return false
end
end
end
This is one of the reasons that factories are generally favored over fixtures in the rails community. Fixtures don't automatically load their associations and tend to be brittle because of it. Your fixture has a product_id of 1, but that product doesn't exist.
I'm not sure exactly how to fix your particular issue, but I would suggest you either:
EDIT
As described here, you could also use label references for associations. So if you had a product fixture called 'tv', you could delete your line_item fixture's product_id field and replace it with product: tv