6

私が書いているバリデータークラスには、呼び出し時に実行される3つの検証がありますMyVariableName.valid?

validates_length_of :id_number, :is => 13, :message => "A SA ID has to be 13 digits long"
validates_format_of :id_number, :with => /^[0-9]+$/, :message => "A SA ID cannot have any symbols or letters"
validate :sa_id_validator

3 つ目はカスタム バリデータです。問題は、バリデーターsa_id_validatorが渡されるデータが 13 桁の数字であることを要求することです。そうしないと、エラーが発生します。validate :sa_id_validator最初の 2 つが実行された後にのみ考慮されるようにするにはどうすればよいですか?

これが非常に単純な質問である場合は申し訳ありませんが、昨日の午後ずっとこれを理解しようとしました。

注: このバリデーターは数千のエントリを実行する必要があり、スプレッドシートのアップロードでも実行されるため、高速である必要があります..

これを行う方法を見ましたが、検証を2回実行する可能性があり、私の場合は悪いでしょう。

編集:

私のカスタムバリデータは次のようになります

def sa_id_validator
  #note this is specific to South African id's
  id_makeup = /(\d{6})(\d{4})(\d{1})(\d{1})(\d{1})/.match(@id_number)
  birthdate = /(\d{2})(\d{2})(\d{2})/.match(id_makeup[1])
  citizenship = id_makeup[3]
  variable = id_makeup[4]
  validator_key = id_makeup[5]

  birthdate_validator(birthdate) && citizenship_validator(citizenship) && variable_validator(variable) && id_algorithm(id_makeup[0], validator_key)
end

private

def birthdate_validator(birthdate)
  Date.valid_date?(birthdate[1].to_i,birthdate[2].to_i,birthdate[3].to_i)
end

def citizenship_validator(citizenship)
  /[0]|[1]/.match(citizenship)
end

def variable_validator(variable)
  /[8]|[9]/.match(variable)
end

def id_algorithm(id_num, validator_key)
  odd_numbers = digits_at_odd_positions
  even_numbers = digits_at_even_positions
  # step1: the sum off all the digits in odd positions excluding the last digit.
  odd_numbers.pop
  a = odd_numbers.inject {|sum, x| sum + x}
  # step2: concate all the digits in the even positions.
  b = even_numbers.join.to_i
  # step3: multiply step2 by 2 then add all the numbers in the result together
  b_multiplied = (b*2)
  b_multiplied_array = b_multiplied.to_s.split('')
  int_array = b_multiplied_array.collect{|i| i.to_i}
  c = int_array.inject {|sum, x| sum + x}
  # step4: add the result from step 1 and 3 together 
  d = a + c
  # step5: the last digit of the id must equal the result of step 4 mod 10, subtracted from 10
  return false unless 
    validator_key == 10 - (d % 10)
  end

  def digits_at_odd_positions
    id_num_as_array.values_at(*id_num_as_array.each_index.select(&:even?))
  end

  def digits_at_even_positions
    id_num_as_array.values_at(*id_num_as_array.each_index.select(&:odd?))
  end

  def id_num_as_array
    id_number.split('').map(&:to_i)
  end
end

属性を検証に追加し、:calculations_ok => true代わりに 12 桁の数字を渡すと、次のエラーが発生します。

i.valid?
NoMethodError: undefined method `[]' for nil:NilClass
from /home/ruberto/work/toolkit_3/toolkit/lib/id_validator.rb:17:in `sa_id_validator'

validates_length_of :id_number??に失敗したはずなのに、カスタム検証に到達していることがわかります。

4

1 に答える 1

2

よくわかりませんが、最初の検証が無効であっても、Railsが常にすべての検証を実行することをブログで読んだことがあります。

あなたができることは、私がすべてのケースを処理するような方法でそれが柔軟または弾むようになるような方法であなたのカスタムメソッドを作ることです。

この答えは間違いなくあなたを助けるでしょう。

それがあなたの質問に答えることを願っています

于 2013-02-26T07:19:59.167 に答える