Rails 4.1 で動く日付時刻用のバリデータを探していたところ、 adzap/validates_timeliness の fork である johncarney/validates_timeliness が Rails 4 に対応しているとのことなので試してみた。
jc-validates_timeliness | RubyGems.org | your community gem host
https://rubygems.org/gems/jc-validates_timeliness
johncarney/validates_timeliness
https://github.com/johncarney/validates_timeliness
環境
% bundle exec rake about
About your application's environment
Ruby version 2.1.3-p242 (x86_64-linux)
RubyGems version 2.2.2
Rack version 1.5
Rails version 4.1.6
JavaScript Runtime Node.js (V8)
Active Record version 4.1.6
Action Pack version 4.1.6
Action View version 4.1.6
Action Mailer version 4.1.6
Active Support version 4.1.6
使ってみる
まずは適当なプロジェクトを作成。
% rails new blog --skip-bundle && cd blog && vim Gemfile
Gemfile に以下を追加
gem 'jc-validates_timeliness'
追記したら bundle install
を実行。
% bundle install
必要なファイルを生成。
% bundle exec rails g validates_timeliness:install
これで以下の設定ファイルが作成される。
- config/initializers/validates_timeliness.rb
- config/locales/validates_timeliness.en.yml
エラーメッセージを日本語で表示するために locale ファイルをコピー。
% cp config/locales/validates_timeliness.en.yml config/locales/validates_timeliness.ja.yml
コピーした validates_timeliness.ja.yml を以下のように変更した。
ja:
errors:
messages:
invalid_date: "は正しい形式で入力してください。"
invalid_time: "は正しい形式で入力してください。"
invalid_datetime: "は正しい形式で入力してください。"
is_at: "は %{restriction} である必要があります。"
before: "は %{restriction} より前を指定してください。"
on_or_before: "は %{restriction} 以前を指定してください。"
after: "は %{restriction} より後を指定してください。"
on_or_after: "は %{restriction} 以降を指定してください。"
validates_timeliness:
error_value_formats:
date: '%Y-%m-%d'
time: '%H:%M'
datetime: '%Y-%m-%d %H:%M'
error_value_formats はバリデーションエラー時に画面上に表示される日付のフォーマットを指定する。
ここでは秒は不要だろ、ということで %S
を除去した。
せっかく日本語リソースを作成したのでついでに config/application.rb にも以下を追記。
config.active_record.default_timezone = :local
config.time_zone = 'Tokyo'
config.i18n.default_locale = :ja
これだけだと日本語リソースがなくてエラーになるので以下も落としてきておく。
% wget -O config/locales/ja.yml https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml
適当な scaffold を作成してマイグレーション実行。
% bundle exec rails g scaffold post title:string body:text published_at:datetime closed_at:datetime
% bundle exec rake db:create db:migrate
model クラスに以下のような感じでバリデーションを追加。
class Post < ActiveRecord::Base
validates :published_at, timeliness: { on_or_after: :now, format: '%Y/%m/%d %H:%M' }, allow_blank: false
validates :closed_at, timeliness: { after: :published_at, format: '%Y/%m/%d %H:%M' }, allow_blank: false
end
lib/validates_timeliness/extensions.rb がまだ 4.1 に完全に対応していないのか、このままだと datetime_select を使うために config.enable_date_time_select_extension!
や config.enable_multiparameter_extension!
を指定した場合にエラーになる。
仕方ないので、View を編集して text_field に変える。
入力はなんか適当な datepicker ライブラリを使うので取り敢えずはこれで良しとする。
<div class="field">
<%= f.label :published_at %><br>
<%= f.text_field :published_at %>
</div>
<div class="field">
<%= f.label :closed_at %><br>
<%= f.text_field :closed_at %>
</div>
上記の設定で
- 日付のフォーマットは秒を除いた
%Y/%m/%d %H:%M
(ex. 2014/11/08 10:30) - published_at は現在日時以降
- closed_at は published_at より後
という条件のバリデーションが設定される。
なんか意外と正式に 4 に対応しているものが見つけられなかったんだけど、定番ってないのだろうか。
参考
[Ruby on Rails] 日付・時刻のバリデーションなら「ValidatesTimeliness」 | CodeNote.net
http://codenote.net/ruby/rails/1797.html
validation - In Rails, how can I validate two date attributes on a comparison basis with validates_timeliness gem? - Stack Overflow
http://stackoverflow.com/questions/13651966/in-rails-how-can-i-validate-two-date-attributes-on-a-comparison-basis-with-vali
validation - Testing that rails model validates date with RSpec - Stack Overflow
http://stackoverflow.com/questions/13138208/testing-that-rails-model-validates-date-with-rspec