如何停止收集<<(object,...)添加重复项?

时间:2011-08-30 18:28:34

标签: ruby-on-rails activerecord associations

鉴于有许多蔬菜模型的晚餐模型,我更喜欢

dinner.vegetables << carrot

如果

,请不要添加胡萝卜
dinner.vegetables.exists? carrot

然而确实如此。它每次都会添加重复记录&lt;&lt;被称为。

你可以在关联上设置一个:uniq选项,但如果有多个,它只能获取并返回一个结果,它不会ENFORCE唯一值。

我可以检查存在吗?每次我将一个obj添加到一个集合中,但这很乏味且容易出错。

我如何使用&lt;&lt;自由而不用担心错误而不是每次检查已经存在的收集成员?

4 个答案:

答案 0 :(得分:2)

最好的方法是使用Set而不是Array:

set = Set.new
set << "a"
set << "a"
set.count  -> returns 1

答案 1 :(得分:1)

如果您有一个表示晚餐和蔬菜之间多对多关系的连接模型,则可以添加ActiveRecord唯一约束。这是我使用联接模型和has_many :through而不是has_and_belongs_to_many的一个原因。如果可能,在数据库级别添加唯一性约束非常重要。

更新:

要使用连接模型来强制执行约束,您需要在数据库中添加一个附加表。

class Dinner
  has_many :dinner_vegetables
  has_many :vegetables, :through => :dinner_vegetables
end

class Vegetable
  has_many :dinner_vegetables
  has_many :dinners, :through => :dinner_vegetables
end

class DinnerVegetable
  belongs_to :dinner
  belongs_to :vegetable

  validates :dinner_id, :uniqueness => {:scope => :vegetable_id} # You should also set up a matching DB constraint
end

答案 2 :(得分:0)

其他海报的想法很好,但作为另一种选择,您也可以使用例如海报在数据库级别强制执行此操作。 UNIQUE constraint in MySQL

答案 3 :(得分:0)

经过大量的挖掘,我发现了一些很酷的东西:before_add,这是一个关联回调,我从来都不知道甚至存在。所以我可以这样做:

  has_many :vegetables, :before_add => :enforce_unique

  def enforce_unique(assoc)
    if exists? assoc
    ...
  end

如果你真的需要这个是独特的,那么在数据库级别这样做是个好主意,但如果它不是关键任务,那么上面的解决方案对我来说已经足够了。

这主要是为了避免在数据库中有额外记录的icky感觉......