Каков наиболее элегантный способ проверки наличия ТОЛЬКО одного из двух атрибутов с использованием Rails? - PullRequest
3 голосов
/ 24 марта 2010
class Followup < ActiveRecord::Base
  belongs_to :post
  belongs_to :comment
end

Эта модель должна иметь только пост или комментарий, но только один из двух.

Вот rspec для того, что я пытаюсь сделать:

  it "should be impossible to have both a comment and a post" do
    followup = Followup.make
    followup.comment = Comment.make
    followup.should be_valid
    followup.post = Post.make
    followup.should_not be_valid
  end

Я вижу множество решений, чтобы сделать это, но что было бы самым элегантным способом сделать это?

Ответы [ 2 ]

7 голосов
/ 24 марта 2010

Я думаю, что вы действительно хотите, это полиморфная ассоциация.

Райан отлично объясняет их в Railscast # 154 .

class Followup < ActiveRecord::Base
  belongs_to :followupable, :polymorphic => true
end

class Post < ActiveRecord::Base
  has_many :followups, :as => :followupable
end

class Comment < ActiveRecord::Base
  has_many :followups, :as => :followupable
end
1 голос
/ 24 марта 2010

Вопрос элегантности, конечно, субъективен, но следующий пример будет делать именно то, что вы хотите, включая отдельные сообщения об ошибках для 2 недопустимых условий, т.е. оба значения предоставлены, а значения не указаны.

class Foo < ActiveRecord::Base  
  validate :one_and_only_one  

  def one_and_only_one()  
    errors.add_to_base("You must provide either a foo or a bar")  
      if self.foo.blank? && self.bar.blank?  
    errors.add_to_base("You cannot provide both a foo and a bar")  
      if !self.foo.blank? && !self.bar.blank?  
  end  
end  

EDIT

Если подумать о большем количестве решений, это может пройти испытание на элегантность лучше

errors.add_to_base("You must provide either a foo or a bar") 
  unless [f.foo, f.bar].compact.length == 1

Хотя это не удастся для полей, заполненных пробелом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...