This is specifically me creating a custom date from from elements. I have a form that collects the day and month of birth of a person (I'm not interested in the year). So I use the following, to create the form entry for the day_and_month_of_birth
element this post is about:
<div class="form-group">
<div class="row">
<div class="col-md-5">Day / Month of Birth</div>
<%= date_select f, :day_and_month_of_birth, builder: fn b -> %>
<div class="col-md-3">
<%= b.(:day, []) %>
</div>
/
<div class="col-md-4">
<%= b.(:month, []) %>
</div>
<% end %>
<%= error_tag f, :day_and_month_of_birth %>
</div>
</div>
In my model I have:
defmodule RocfDev.Registration do
use RocfDev.Web, :model
schema "registration" do
field :title, :string, virtual: true
field :firstname, :string, virtual: true
field :surname, :string, virtual: true
field :day_and_month_of_birth, Ecto.Date, virtual: true
end
def changeset(model, params \\ %{}) do
model
|> cast(params, [
:title,
:firstname,
:surname,
:day_and_month_of_birth
])
end
Currently when I post the form, I get the error unrecognized date %{"day" => "1", "month" => "1"}
.
I suppose it's because there's no day
and month
field in the registration
schema. My questions are:
1st, Since I'm not interested in the year of birth, is Ecto.Date still the appropriate type to use for the day_and_month_of_birth
field?
2nd, How do I resolve the error?
Basically, you have two integer ranges
1..12
and1..31
. But there are tons of limitations/constraints on their pair:2
and30
is invalid, etc. That’s whyEcto.Date
type is still looking applicable here. To use it, one might force the year to always be, say,2000
, and pass this value back and forth to your frontend, using the hidden field to “display” it and pass back. That way you could not care aboutunrecognized date
errors: from now on you’ll get%{"year" => 2000, "day" => "1", "month" => "1"}
here.On the other hand, just day and month value is an incomplete information to verify the date, due to leap years existence. You can’t prove whether
February, 29
is a valid date of birth or not, without knowing the year.2016/2/29
is valid, while2017/2/29
is not. From this point of view, it sounds reasonable to quit abusingEcto.Date
and use just two range fields, both of type integer.