Hi, I have the following situation. I have two models Item and Genre. A Item has a name and a description. The genres-table contains a list of possible genres wich can be associated to items. So a Item could be associated with many genres and a genre could be associated with many items. A typically n:m-relationship. I use the :has_many-:through association, because i want do to a kind of on-delete-cascade in Rails. My models look as follows:
class Item < ActiveRecord::Base # n:m relationship between items and genres has_many :items_genres, :dependent => :destroy has_many :genres, :through => :items_genres
validates_presence_of :name
validate :must_have_at_least_one_associated_genre
protected # valdation to ensure, that a item has at least one associated genre def must_have_at_least_one_associated_genre # add an error message to the default error messages errors.add(:genres, "must_be_choosen") if # if no genre is associated with this item genres.size <= 0 end
end
I put two validations to the Item. The statement at line 6 make the name arrtibute mandatory. In addition I would to ensure that a item has at least one associated genre. So I decided to write a own validation-method (line 10-17).
class ItemsGenre < ActiveRecord::Base belongs_to :item belongs_to :genre end
class Genre < ActiveRecord::Base # n:m relationship between genres and items has_many :items_genres, :dependent => :destroy has_many :items, :through => :items_genres end
I added some unit-tests to ensure that the validation works as aspected. I wrote the following unit-test-methods.
require 'test_helper'
class ItemTest < ActiveSupport::TestCase
def test_should_create_an_item item = Item.new( :name => "Item-Name", :description => "Item-Description" )
# Assert, that the item is not valid and cannot be saved, # because there are no genres associated with it assert !item.valid? assert !item.save
# Associate two genres with this item item.genres = Genre.find_all_by_id([genres(:club).id, genres (:commedy).id])
# Assert, that the item is now valid and can be saved assert item.valid? assert item.save
# Check if there are two genres associated with this item assert_equal 2, item.genres.size end
def test_should_require_name # Create an item-object, but set name nil item = Item.new( :name => nil, :description => "Item-Description" ) # Assert, that the item is not valid and cannot be saved, # because the name is nil assert !item.valid? assert !item.save end
def test_should_require_description # Create an item-object, but set name to nil item = Item.new( :name => "Item-Name", :description => nil ) # Assert, that the item is not valid and cannot be saved, # because the description is nil assert !item.valid? assert !item.save end
end
The amazing thing is that all tree test-methods pass. But I only have a validation for the name and the asscociated genres. I do not have a validation of the description, but the test method for the description passes.
I found out another thing. If I remove the validate-call in line 8 of the Item-model, then all test-methods work as aspected. In this case the test_should_create_an_item- and the test_should_require_description-method both fail and the test_should_require_name-method passes.
If I run the application and try to add a new item by the new-form, all validation works as exspected. So it seems that only the unit-test are faulty.
I am at a loss. I don´t know what I am doing wrong. Can anyone reproduce this behavior? Or can anyone tell me how to write a validation-method to ensure that at least one genre is associated with an item. Maybe my test-method is wrong.
I hope someone can help me out.