【问题标题】:Setup and Testing to prevent duplication in ActiveRecord many to many relationship设置和测试以防止 ActiveRecord 多对多关系中的重复
【发布时间】:2014-09-12 02:29:08
【问题描述】:

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

并且“项目”不应该有重复的“颜色”, 例如:- 如果“Item1”有“Blue”和“Red”,那么我们不能将另一个“Red”添加到“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"

请指教。

【问题讨论】:

    标签: activerecord ruby-on-rails-4 rspec


    【解决方案1】:

    当您添加第二种颜色时,它是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
    

    【讨论】:

    • @snackmoore 这对您有什么帮助吗?
    • 抱歉回复晚了。由于开放ID问题,我几天无法登录。我喜欢 2 选项,但我如何用错误消息提醒用户?
    • 我认为您不需要错误消息。即使用户多次尝试添加相同的颜色,系统也将始终只保存一个,因为它就像一组一样。在用户体验方面,恕我直言,可以抑制错误消息,很可能 b/c 用户会尝试错误地添加现有颜色。最终他们的操作将产生预期的结果,并且不会引发错误。不过,如果您真的想警告您的用户,我已经使用示例解决方案更新了答案。
    猜你喜欢
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 2017-02-22
    • 2013-06-10
    相关资源
    最近更新 更多