开发者

How can I stop collection<<(object, …) from adding duplicates?

Given a Dinner model that has many Vegetable models, I would prefer that

dinner.vegetables << carrot

not add the carrot if

dinner.vegetables.exists? carrot开发者_如何学C

Yet it does. It will add a duplicate record every time << is called.

There is a :uniq option you can set on the association, but it only FETCHES AND RETURNS one result if there are multiples, it doesn't ENFORCE unique values.

I could check for exists? every time I add an obj to a collection, but that is tedious and error-prone.

How can I use << freely and not worry about errors and not check for already existing collection members every time?


The best way is to use Set instead of Array:

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


You can add an ActiveRecord unique constraint if you have a join model representing a many-to-many relationship between dinners and vegetables. That's one reason I use join models and has_many :through as opposed to has_and_belongs_to_many. It's important to add a uniqueness constraint at the database level if possible.

UPDATE:

To use a join model to enforce constraint you would need an additional table in your database.

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


The other posters' ideas are fine, but as another option you can also enforce this on the database level using e.g. the UNIQUE constraint in MySQL.


After a lot of digging, I've discovered something cool: before_add, which is an association callback, which I never knew even existed. So I could do something like this:

  has_many :vegetables, :before_add => :enforce_unique

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

Doing this at the DB level is a great idea if you REALLY NEED this to be unique, but in the case that it's not mission critical the solution above is enough for me.

It's mostly to avoid the icky feeling of having extra records lying around in the db...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜