-
Notifications
You must be signed in to change notification settings - Fork 183
How to do a multipart updatable date
bethesque edited this page Dec 8, 2014
·
7 revisions
Handles multipart dates, allowing for the initial date to be nil.
require 'minitest/autorun'
require 'date'
require 'reform' # 1.2.2
Person = Struct.new(:date_of_birth)
class DateForm < Reform::Form
reform_2_0!
property :day
property :month
property :year
validate :validate_date
def validate_date
# Need a more elegant way to add error to base of date_of_birth.
# Using :base will add the error to the Person object.
# Can't hardcode the message to "Date of birth ..."
# because this form can be used for
# more than one date property.
unless valid_date?
errors.add(:'', "is not a valid date")
end
end
def date
Date.parse("#{year}-#{month}-#{day}")
end
def valid_date?
date
true
rescue ArgumentError => e
false
end
end
class PersonForm < Reform::Form
reform_2_0!
NilDate = Struct.new(:year, :month, :day)
property :date_of_birth,
form: DateForm,
populate_if_empty: NilDate,
# virtual: true
writeable: false
def date_of_birth
super || DateForm.new(NilDate.new)
end
def sync
result = super
model.date_of_birth = date_of_birth.date
result
end
end
describe PersonForm do
let(:date) { nil }
let(:person) { Person.new(date) }
let(:form_data) do
{
"date_of_birth" => {
"day" => "2",
"month" => "1",
"year" => "2000",
}
}
end
subject { PersonForm.new(person) }
describe "date_of_birth" do
describe "with a date" do
let(:date) { Date.new(2014, 1, 2) }
it "is a DateForm" do
assert_kind_of(DateForm, subject.date_of_birth)
end
describe "day" do
it 'returns the day' do
assert_equal(2, subject.date_of_birth.day)
end
end
describe "month" do
it 'returns the month number' do
assert_equal(1, subject.date_of_birth.month)
end
end
describe "year" do
it 'returns the year' do
assert_equal(2014, subject.date_of_birth.year)
end
end
end
describe "with a nil date" do
it "is a DateForm" do
assert_kind_of(DateForm, subject.date_of_birth)
end
describe "day" do
it 'returns nil' do
assert_nil(subject.date_of_birth.day)
end
end
describe "month" do
it 'returns nil' do
assert_nil(subject.date_of_birth.month)
end
end
describe "year" do
it 'returns nil' do
assert_nil(subject.date_of_birth.year)
end
end
end
end
describe "validate" do
before do
subject.validate(form_data)
end
describe "with an invalid date" do
let(:form_data) do
{
"date_of_birth" => {
"day" => "30",
"month" => "2",
"year" => "2000",
}
}
end
it 'returns an error' do
assert_equal(["Date of birth is not a valid date"], subject.errors.full_messages)
end
end
describe "with a valid date" do
it "does not return an error" do
assert_empty(subject.errors)
end
end
end
describe "sync" do
before do
subject.validate(form_data)
subject.sync
end
describe "with an existing date" do
let(:date) { Date.new(2014, 3, 4) }
it "sets the date_of_birth" do
assert_equal(Date.new(2000, 1, 2), person.date_of_birth)
end
end
describe "with no existing date" do
it "sets the date_of_birth" do
assert_equal(Date.new(2000, 1, 2), person.date_of_birth)
end
end
end
end