##やりたいこと
2014-9-31 などを弾きたい。
##結論から
ActiveModel::EachValidator を使った Custom Validator を追加します。
##gem を使わない理由
- gem を使わなくても良いくらいの規模。
- rails のバージョンアップに伴う、gem バージョンアップの負債が増えるのがいやだった。
- 例えば rails v4.1.5 で validates_timeliness を使うと、以下のような deprecated なエラーが出るようになった。
class MyValidator < ActiveModel::Validator
def initialize(options={})
super
options[:class].send :attr_accessor, :custom_attribute
end
end
. (called from <class:Miko> at /Users/mikosan/mikosan_no_path/mikofuku.rb:1)
W, [2014-09-12T13:52:35.984731 #6011] WARN -- : DEPRECATION WARNING: The `Validator#setup` instance method is deprecated and will be removed on Rails 4.2. Do your setup in the constructor instead:
class MyValidator < ActiveModel::Validator
def initialize(options={})
super
options[:class].send :attr_accessor, :custom_attribute
end
end
. (called from <class:Miko> at /Users/mikosan/mikosan_no_path/mikofuku.rb:1)
##書いたもの
日付の正当性をチェックします。
フォーマットは YYYY/MM/DD(例:2014/9/12) に固定します。
※もしフレキシブルにする場合には、4行目や7行目へ適宜手を入れて下さい。
app/validators/date_validator.rb
class DateValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << I18n.t('errors.messages.invalid_date_format') unless /\A\d{1,4}\-\d{1,2}\-\d{1,2}\Z/ =~ value
begin
(y,m,d) = value.split('-')
Time.local(y, m, d, 0, 0, 0)
rescue
record.errors[attribute] << I18n.t('errors.messages.invalid_date')
end
end
end
対応するエラーメッセージを登録します。
config/locales/ja.yml
ja:
...
errors:
messages:
invalid_date: の指定が不正です。
invalid_date_format: の形式が不正です。
呼び出す側は通常の CustomValidator と同じく、
app/models/hoge.rb
class Hoge
include ActiveModel::Model
attr_accessor :assigned_date
validates :assigned_date, date: true
end
などと記述して、Controller 側で valid?
することで呼び出せます。
##とはいえ...
フォーマットが固定なのは不便ですし、何も考えずにぼーんと日付っぽい文字列を渡して validation してもらいたい気持ちもあるのでその辺りの実装を盛り込んでおきたい気もします。
しかし、そこまでするなら gem にしたほうが良いのでは?とも思います。
ひとまずはここに落ち着きましたが、うーん。
##時刻は?
上記日付の validation を流用すれば簡単に作れますので、割愛します。