我有以下类用于“项目”和“颜色”之间的多对多关系。
并且“项目”不应该有重复的“颜色”, 例如:- 如果“Item1”有“Blue”和“Red”,那么我们不能向“Item1”添加另一个“Red”
这是正确的设置方式吗?
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"
请指教。
最佳答案
当你加上第二种颜色时,就是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
关于activerecord - 设置和测试以防止 ActiveRecord 中的重复多对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25799815/