Help us understand the problem. What is going on with this article?

Rails 4.1 で validates_timeliness を使う

More than 5 years have passed since last update.

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 に以下を追加

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 を以下のように変更した。

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/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 クラスに以下のような感じでバリデーションを追加。

app/models/post.rb
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 ライブラリを使うので取り敢えずはこれで良しとする。

app/views/posts/_form.html.erb
<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

akishin
プログラマです。 Ruby が好きです。 最近は仕事では PHP とか Azure とか触ってます。 できれば仕事でも Ruby が書きたいです。
https://akishin.hatenablog.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away