length: {maximum: 10} みたいなvalidatorを作る(is_a ActiveModel::EachValidator)

# Example
#     validates :email, email: true

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    fuzzy_valid_email_regexp = //
    record.errors.add(attribute, :invalid_email) unless fuzzy_valid_email_regexp =~ value
  end
end

みたいなのは作ったことあったけど、任意の値を渡したくなるvalidatorを書くことがなかったので知らなかった。

UTF-8の文字列を扱ってるシステムなんだけど、深淵な理由からSJISエンコードした時のbytesizeでvalidationしないといけないみたいな要件があり、調べた。特に特別にやらないといけないことはなかった。

# Example
#     validates :email, sjis_bytesize: {maximum: 100}

class SjisBytesizeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    sjis_bytesize = ほげほげ value
    if sjis_bytesize > options[:maximum]
      record.errors.add(attribute, :too_long, count: [:maximum])
    end
  end
end

みたいに optionsを参照すれば良い。渡した値を事前に加工したりチェックしたければ initialize でごにょごにょした後にsuper呼んどけば良い。

c.f.