achedeuzot
Ecto_commons – Ecto common helper functions such as Changeset validators
This library contains common helpers used with Ecto.Changeset.
I noticed myself copying over validators from various projects multiple times. So I figured I’d create a common library. I know everyone likes to have their own validation logic but I tried keeping it as generic as possible so it’ll be useful for many situations.
For now, it contains validators for the following cases:
-
Date,DateTimeandTime -
EmailValidator: validate emails and exclude temporary email providers -
URLValidator: validate URLs with various levels of strictness -
StringValidator: validate a string has a given prefix -
PostalCodeValidator: validate postal codes for multiple countries (to be improved) -
SocialSecurityValidator: validate social security number (SSN) -
LuhnValidator: validate Luhn-type numbers such as credit card numbers and other administrative codes.
Happy to receive feedback, pull requests from motivated folks and ideas for improvement
I hope this lib will grow into a set of good common ecto helpers and tools we can all benefit from.
Cheers !
Most Liked
achedeuzot
Hi folks !
I’ve published v0.2.0 with your feedbacks.
- I’ve improved the URLValidator by better documenting what is and what isn’t supported.
- I’ve added all countries for the PostalCodeValidator (still no full database but a first sanity check of the format). The formats come from http://i18napis.appspot.com/, recommended by the (now deprecated) unicode postal code database.
- I’ve added better documentation to EmailValidator and an
opt-inapproach to which checks you want to apply. I also addedpow's package email validator and fixed some of the shortcomings found by @hauleth. - I’ve added the
validate_manyhelper as it’s indeed common to validate multiple fields with the same options.
As usual, happy to have your feedbacks, issues and pull requests 
Cheers 
Kurisu
Another helper I used not exactly for changeset but when using Ecto.Multi:
@doc """
Normalize Ecto.Multi transaction result so it returns
{:ok, value} or {:error, failed_value}
"""
def normalize(result, key \\ nil)
def normalize({:error, _, failed_value, _}, _key), do: {:error, failed_value}
def normalize({:ok, result}, key), do: {:ok, Map.get(result, key, result)}
def normalize(result, _key), do: result
Example of usage:
def create_slider(attrs \\ %{}) do
changeset = Slider.changeset(%Slider{}, attrs)
Multi.new()
|> Multi.insert(:slider, changeset)
|> Multi.update(:slider_with_image, &Slider.image_changeset(&1.slider, attrs))
|> Repo.transaction()
|> MyLib.Multi.normalize(:slider_with_image)
end
This way in the Phoenix controller we don’t have to change the classic way to handle CRUD actions.
hauleth
Seems that this is still not fully valid, as this do not allow [::1] as a domain part. Additionally it will allow .foo. as a domain, which is incorrect.
danschultzer
Good catch, thanks! Didn’t validate the domain properly.
I didn’t add IP addresses as it’s strongly discouraged with RFC 3696:
The domain name can also be replaced by an IP address in
square brackets, but that form is strongly discouraged except for
testing and troubleshooting purposes.
@achedeuzot you may want to take a look at the changes in Improve email validation · Issue #560 · pow-auth/pow · GitHub as I didn’t validate the domain properly. Each DNS label should be validated. There are also some additional validation that I didn’t include such as checking for reserved domains (like example.com, these domains can’t receive e-mail).
hauleth
If you are making it into library, then make it correct validator. Or at least mention that it will match only on subset of possible addresses.
Why use custom regex for validating URL instead, well, URI module? Also, why is regex strictly allowing only HTTP(s) and FTP protocols? What about other like for example Gopher or IRC?
Well, without DB to lookup these postal codes, this validator makes little sense. In most cases you can get list of all possible postal codes for given country, so it should be quite simple to make them into in-memory database.







