对于“Item”和“Color”之间的多对多关系,我有以下类。
“项目”不应该有重复的“颜色”, 例如:- 如果“Item1”具有“Blue”& “红色”然后我们不能将另一个“红色”添加到“Item1”
这是设置它的正确方法吗?
class Item < ActiveRecord::Base
has_many :item_colors
has_many :colors, :through => item_colors
end
class Color < ActiveRecord::Base
has_many :item_colors
has_many :items, :through => item_colors
end
class ItemColor < ActiveRecord::Base
belongs_to :item
belongs_to :color
validates_uniqueness_of :color, scope: :item
end
我对重复颜色的测试。它是如何测试的吗?
describe "item should not have duplicated colors" do
before do
@item = FactoryGirl.create(:item)
@color1 = FactoryGirl.create(:color)
@item.colors << @color1
@item.colors << @color1
@item.save
end
it { should_not be_valid }
end
当我在rails控制台中尝试此操作时,当我向项目添加重复的颜色时,它将失败
但是我没有在item.errors.message
中收到错误消息,而是获得了ActiveRecord异常
"ActiveRecord::RecordInvalid: Validation failed: Color has already been taken"
请告知。
答案 0 :(得分:3)
添加第二种颜色时,它是automatically saved,因为父对象@item
已经保存,即它不是new_record
。
鉴于它是一个has_many :through
关联,它是always saved with the bang version of save!
,这反过来会引发异常,因为您的连接模型ItemColor
无法验证唯一性。
在您的情况下,您有两种选择:
rescue
例外并手动管理错误消息; 如果你只是为了添加验证层而使用连接模型,你可以摆脱它,改为使用HABTM并将关联作为一个集来处理,例如。
> item = FactoryGirl.create(:item)
> color = FactoryGirl.create(:color)
> 10.times { item.colors |= [color] } # you can add it n times...
> item.colors.count # => 1 ...still only one is saved b/c it is a union set.
听起来怎么样?
更新:如果您确实要显示错误消息,可以,例如
if item.colors.include?(color)
item.errors.add(:colors, "color already selected")
else
item.colors |= [color]
end