所有值都相同的符号验证

时间:2010-09-23 14:02:42

标签: ruby-on-rails validation

用户应插入所有正值或负值。

我如何设置相同的符号验证?

对,我在before_save上写了这个..

unless (self.alt_1 >= 0 && self.alt_2 >=0 && self.alt_3 >= 0 &&
      self.alt_4  >= 0 && self.alt_5 >= 0 && self.alt_6 >= 0) ||
    (self.alt_1 <= 0 && self.alt_2 <=0 && self.alt_3 <= 0 &&
      self.alt_4  <= 0 && self.alt_5 <= 0 && self.alt_6 <= 0)
  self.errors.add_to_base(_("All values sign should be same."))
end

3 个答案:

答案 0 :(得分:3)

first_sign = self.alt_1 <=> 0

(2..6).each do |n|
  unless (self.send("alt_#{n}") <=> 0) == first_sign
    errors.add_to_base(_("All values' signs should be same."))
    break
  end
end

使用此方法,我们首先获得alt_1的符号,然后查看其余元素(alt_2到alt_6)的符号是否匹配。一旦我们找到一个不匹配的,我们就添加验证错误并停止。它将运行最多6次迭代,最少2次。


另一个更聪明但效率更低的方法是使用方便的方法Enumerable#all?,如果传递给它的块返回true,则返回true:

range = 1..6

errors.add_to_base(_("All values' signs should be same.")) unless
  range.all? {|n| self.send("alt_#{n}") >= 0 } ||
  range.all? {|n| self.send("alt_#{n}") <= 0 }

这里我们首先检查所有元素是否大于0,然后检查所有元素是否小于0.此方法最多迭代12次,最少6次。

答案 1 :(得分:1)

以下是一种略有不同的方法:

irb(main):020:0> def all_same_sign?(ary)
irb(main):021:1>   ary.map { |x| x <=> 0 }.each_cons(2).all? { |x| x[0] == x[1] }
irb(main):022:1> end
=> nil
irb(main):023:0> all_same_sign? [1,2,3]
=> true
irb(main):024:0> all_same_sign? [1,2,0]
=> false
irb(main):025:0> all_same_sign? [-1, -5]
=> true

我们使用the spaceship operator来获取每个数字的符号,并确保每个元素与其后面的元素具有相同的符号。您还可以通过执行

将其重写为更懒惰
ary.each_cons(2).all? { |x| (x[0] <=> 0) == (x[1] <=> 0) }

但在我看来这不太可读。

答案 2 :(得分:0)

unless 
  [:<=, :>=].any? do |check|
    # Check either <= or >= for all values
    [self.alt1, self.alt2, self.alt3, self.alt4, self.alt5, self.alt6].all? do |v|
      v.send(check, 0)
    end
  end
  self.errors.add_to_base(_("All values sign should be same."))
end