Fields
A collection of commonly used fields implemented as custom Ecto types
with the validation, sanitising and encryption/hashing.
Installation
Add the fields package to your list of dependencies in mix.exs:
def deps do
[
{:fields, "~> 1.0.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/fields.
Usage
Each field can be used in place of an Ecto type when defining your schema.
schema "users" do
field(:email, Fields.EmailEncrypted)
field(:address, Fields.Address)
field(:postcode, Fields.Postcode)
field(:password, Fields.Password)
timestamps()
end
Each field is defined as an
Ecto type,
with the relevant callbacks.
So when you call Ecto.Changeset.cast/4
in your schema's changeset function,
the field will be correctly validated.
For example, calling cast on the :email field
will ensure it is a valid format for an email address.
When you load one of the fields into your database,
the corresponding dump/1 callback will be called,
ensuring it is inserted into the database in the correct format.
In the case of Fields.EmailEncrypted,
it will encrypt the email address
using a given encryption key
(set in your config file) before inserting it.
Likewise, when you load a field from the database,
the load/1 callback will be called,
giving you the data in the format you need.
Fields.EmailEncrypted will be decrypted back to plaintext.
Each Field optionally defines an input_type/0 function.
This will return an atom
representing the Phoenix.HTML.Form input type to use for the Field.
For example: Fields.DescriptionPlaintextUnlimited.input_type returns :textarea.
The fields DescriptionPlaintextUnlimited
and HtmlBody uses
html_sanitize_ex
to remove scripts and help keep your project safe.
HtmlBody is able to display basic html elements
whilst DescriptionPlaintextUnlimited displays text.
Remember to use raw when rendering
the content of your DescriptionPlaintextUnlimited
and HtmlBody fields
so that symbols such as & (ampersand) and Html are rendered correctly.
E.g:
<p><%= raw @product.description %></p>
The currently existing fields are:
- Address
- AddressEncrypted
- DescriptionPlaintextUnlimited
- Encrypted
- EmailPlaintext
- EmailHash
- EmailEncrypted
- Hash
- HtmlBody
- Password
- PhoneNumber
- PhoneNumberEncrypted
- Postcode
- PostcodeEncrypted
- Url
Config
If you use any of the Encrypted fields,
you will need to set a list of
one or more encryption keys in your config:
config :fields, Fields.AES,
keys:
System.get_env("ENCRYPTION_KEYS")
# remove single-quotes around key list in .env
|> String.replace("'", "")
# split the CSV list of keys
|> String.split(",")
# decode the key.
|> Enum.map(fn key -> :base64.decode(key) end)
If you use any of the Hash fields, you will need to set a secret key base:
config :fields, Fields,
secret_key_base: "rVOUu+QTva+VlRJJI3wSYONRoffFQH167DfiZcegvYY/PEasjPLKIDz7wPTvTPIP"
Background / Further Reading
How to Create a Re-useable Elixir Package and Publish to hex.pm
- https://hex.pm/docs/publish
- https://medium.com/kkempin/how-to-create-and-publish-hex-pm-package-elixir-90cb33e2592d
- https://medium.com/blackode/how-to-write-elixir-packages-and-publish-to-hex-pm-8723038ebe76