activerecord - 设置和测试以防止 ActiveRecord 中的重复多对多关系

标签 activerecord ruby-on-rails-4 rspec

我有以下类用于“项目”和“颜色”之间的多对多关系。

并且“项目”不应该有重复的“颜色”, 例如:- 如果“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 无法验证唯一性。

在您的情况下,您有两种选择:

  1. rescue 异常并手动管理错误消息;
  2. 如果您使用连接模型只是为了添加验证层,您可以去掉它,使用 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/

相关文章:

ruby-on-rails - 修改特定迁移

ruby-on-rails - 如何防止加载 RSpec 助手

ruby-on-rails - 如何摆脱 let using before

ruby-on-rails - 在没有 Rails 的情况下运行 ActiveRecord 迁移

ruby-on-rails - 连续两行的最大列差

ruby-on-rails - ActiveRecord 查询的返回类型

javascript - AngularJS + Rails : Unknown provider: e

ruby-on-rails - 如何在 Rails 中以 mb 为单位获取 ruby​​ 对象的大小?

ruby-on-rails - rails-根据浏览器时区和 start_date 将时间转换为 UTC

ruby-on-rails - 来自 Controller 的 Rspec 测试邮件程序,并在帮助程序中使用参数