elmt
elmt

Reputation: 1634

validates_one_of

I have a table that contains a column for a boolean value. I want there to be only one row that can have that boolean value be true. Does rails support such a feature?

I'm looking for something like the following:

Table  
id | bool_value
1  | false
2  | false
3  | true
4  | false

Upvotes: 4

Views: 1302

Answers (3)

Dean Radcliffe
Dean Radcliffe

Reputation: 2206

validates_uniqueness_of :enabled, :if => :enabled is a pretty hack, but you have a problem with your design if you are spreading one conceptual bit of true/falseness across multiple records. This is going to perform/scale poorly, and can allow for inconsistency to creep in.

Lets look at some alternatives in a world where only one Answer can be Top Answer.

Scenario 1: Instead of an is_top_answer column on Answer, you have in some other table a field called top_answer_id, referring to an answer.

class Site; has_one :top_answer, :class => :answer; end

Clearly now there can be only one, and setting and getting become trivially easy, compared to the table scans your design requires.

Scenario 2: Answer has a foreign key to Question, and there can only be one top answer per question. You can extend the previous solution by having top_answer_id in the question table. Its common that the previous scenario will grow into this one over time.

Depending on your needs, you may also want to consider not rejecting a second boolean being true, in an after_save (part of the same transaction), simply setting all others to false. It's hardly more work than scanning the entire table to see whether it's allowed to set the current record to true.

Upvotes: 4

Geoff Lanotte
Geoff Lanotte

Reputation: 7510

You can do this, which would only validate the uniqueness if enabled was set to true and would ignore other cases (nil and false), because nil == false:

validates_uniqueness_of :enabled, :if => :enabled

That should cover all cases.

Hope this helps!

Upvotes: 9

Harish Shetty
Harish Shetty

Reputation: 64373

Try this:

validates_each :bool_value do |record, attr, value|
  if value and Table.count(:conditions => {:bool_value => true}) > 0
    record.errors.add attr, 'There can only be one TRUE row'
  end
end

Refer to the ActiveRecord documentation for more details.

Upvotes: 1

Related Questions