mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-04 22:16:08 +00:00
Add validator for datetime string
Example usage:
validates :start_at, date_time_string: true
This commit is contained in:
63
app/validators/date_time_string_validator.rb
Normal file
63
app/validators/date_time_string_validator.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
# Validates a datetime string with relaxed rules
|
||||
#
|
||||
# This uses ActiveSupport::TimeZone.parse behind the scenes.
|
||||
#
|
||||
# https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-parse
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class Post
|
||||
# include ActiveModel::Validations
|
||||
#
|
||||
# attr_accessor :published_at
|
||||
# validates :published_at, date_time_string: true
|
||||
# end
|
||||
#
|
||||
# post = Post.new
|
||||
#
|
||||
# post.published_at = nil
|
||||
# post.valid? # => true
|
||||
#
|
||||
# post.published_at = ""
|
||||
# post.valid? # => true
|
||||
#
|
||||
# post.published_at = []
|
||||
# post.valid? # => false
|
||||
# post.errors[:published_at] # => ["must be a string"]
|
||||
#
|
||||
# post.published_at = 1
|
||||
# post.valid? # => false
|
||||
# post.errors[:published_at] # => ["must be a string"]
|
||||
#
|
||||
# post.published_at = "2018-09-20 01:02:00 +10:00"
|
||||
# post.valid? # => true
|
||||
#
|
||||
# post.published_at = "Not Valid"
|
||||
# post.valid? # => false
|
||||
# post.errors[:published_at] # => ["must be valid"]
|
||||
class DateTimeStringValidator < ActiveModel::EachValidator
|
||||
NOT_STRING_ERROR = I18n.t("validators.date_time_string_validator.not_string_error")
|
||||
INVALID_FORMAT_ERROR = I18n.t("validators.date_time_string_validator.invalid_format_error")
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
return if value.nil? || value == ""
|
||||
|
||||
validate_attribute_is_string(record, attribute, value)
|
||||
validate_attribute_is_datetime_string(record, attribute, value)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def validate_attribute_is_string(record, attribute, value)
|
||||
return if value.is_a?(String)
|
||||
|
||||
record.errors.add(attribute, NOT_STRING_ERROR)
|
||||
end
|
||||
|
||||
def validate_attribute_is_datetime_string(record, attribute, value)
|
||||
return unless value.is_a?(String)
|
||||
|
||||
datetime = Time.zone.parse(value)
|
||||
record.errors.add(attribute, INVALID_FORMAT_ERROR) if datetime.blank?
|
||||
end
|
||||
end
|
||||
@@ -100,6 +100,11 @@ en:
|
||||
order_cycle:
|
||||
cloned_order_cycle_name: "COPY OF %{order_cycle}"
|
||||
|
||||
validators:
|
||||
date_time_string_validator:
|
||||
not_string_error: "must be a string"
|
||||
invalid_format_error: "must be valid"
|
||||
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
|
||||
58
spec/validators/date_time_string_validator_spec.rb
Normal file
58
spec/validators/date_time_string_validator_spec.rb
Normal file
@@ -0,0 +1,58 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe DateTimeStringValidator do
|
||||
class TestModel
|
||||
include ActiveModel::Validations
|
||||
|
||||
attr_accessor :timestamp
|
||||
|
||||
validates :timestamp, date_time_string: true
|
||||
end
|
||||
|
||||
describe "internationalization" do
|
||||
it "has translation for NOT_STRING_ERROR" do
|
||||
expect(described_class::NOT_STRING_ERROR).not_to be_blank
|
||||
end
|
||||
|
||||
it "has translation for INVALID_FORMAT_ERROR" do
|
||||
expect(described_class::INVALID_FORMAT_ERROR).not_to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
describe "validation" do
|
||||
let(:instance) { TestModel.new }
|
||||
|
||||
it "does not add error when nil" do
|
||||
instance.timestamp = nil
|
||||
expect(instance).to be_valid
|
||||
end
|
||||
|
||||
it "does not add error when blank string" do
|
||||
instance.timestamp = nil
|
||||
expect(instance).to be_valid
|
||||
end
|
||||
|
||||
it "adds error NOT_STRING_ERROR when blank but neither nil nor a string" do
|
||||
instance.timestamp = []
|
||||
expect(instance).not_to be_valid
|
||||
expect(instance.errors[:timestamp]).to eq([described_class::NOT_STRING_ERROR])
|
||||
end
|
||||
|
||||
it "adds error NOT_STRING_ERROR when not a string" do
|
||||
instance.timestamp = 1
|
||||
expect(instance).not_to be_valid
|
||||
expect(instance.errors[:timestamp]).to eq([described_class::NOT_STRING_ERROR])
|
||||
end
|
||||
|
||||
it "does not add error when value can be parsed" do
|
||||
instance.timestamp = "2018-09-20 01:02:00 +10:00"
|
||||
expect(instance).to be_valid
|
||||
end
|
||||
|
||||
it "adds error INVALID_FORMAT_ERROR when value cannot be parsed" do
|
||||
instance.timestamp = "Not Valid"
|
||||
expect(instance).not_to be_valid
|
||||
expect(instance.errors[:timestamp]).to eq([described_class::INVALID_FORMAT_ERROR])
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user