代码之家  ›  专栏  ›  技术社区  ›  marcgg

使用rails验证两个属性中只有一个存在的最优雅的方法是什么?

  •  3
  • marcgg  · 技术社区  · 15 年前
    class Followup < ActiveRecord::Base
      belongs_to :post
      belongs_to :comment
    end
    

    这个模型只需要一个post或一个comment,但只需要其中的一个。

    以下是我要做的事情的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 回复  |  直到 15 年前
        1
  •  7
  •   Chap    15 年前

    我认为你真正想要的是多态性关联。

    Ryan很好的解释了 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
    
        2
  •  1
  •   Steve Weet    15 年前

    优雅的问题当然是主观的,但下面的示例将完全满足您的要求,包括两个无效条件(即提供的值和不提供的值)的单独错误消息。

    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  
    

    编辑

    考虑更多的解决方案,这样就可以更好地通过优雅测试

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

    虽然这将失败的空间填充字段。