View Source Eakins.Schema (eakins v0.0.1)
A schema extension that allows you to attach images to a model.
To use this extension, your schema must define an integer
field called :version
and a map field. The map field's name
should be the same as the image map or image list that you will define.
To configure this module, just use
it below your usage of Eakins.Schema
.
Then, define eith an image_map
or image_list
in your schema.
defmodule Myapp.User do
use Ecto.Schema
use Eakins.Schema
schema "users" do
field :first_name, :string
field :last_name, :string
image_map :avatars
end
end
The previous incantation will define an image map and associate with the images
field.
The name of the image list or the image map should be plural, as the functions that are
generated make use of this name to provide access to the entire list (the plural functions)
or a single image (the singular functions).
Image Maps
An image map is an unordered collection of named images. Eakins in this collection can
be added, removed or accessed by their name. Similarly, you can use the generated functions
to retrieve a displayable instance at any aspect ratio or size. If the name of the image map is
images
, the following functions are generated:
display_image/4
- Returns a displayable instance of the named imagedisplay_images/3
- Returns all images associated with this model. The return values are displayable.find_image/2
- Finds the image with the given namedelete_image/2
- Deletes the image with the given namehas_image?/2
- Returns true if there is an image with the given nameput_image/3
- Sets the image with the given name, replacing any existing image.find_image/2
- Finds the image on this model with the given name. The returned image is not displayable
Image Lists
An image list is an ordered list of images,. Images in an image list are able to be retrieved, deleted and added by index
If the name of the image list is images
, the following functions are generated:
display_image/4
- Returns a displayable image with the given index or nil if one doesn't exist.display_images/3
- Returns all images in the image list at the given aspect ratio and height.find_image/2
- Returns the image with the given index, if it exists and nil otherwise.delete_image_at/2
- When applied to a changeset, deletes the image with the given index.replace_image_at/3
- Sets the image with the given index on this image list. This will replace any image with the same index.insert_image_at/3
- Inserts an image into the image list at the specified index. This will grow the listimage_at
/2 - Finds the image in this image list with the given index. The returned image is not displayable.
Generated functions
Adding an image list or an image map to your model creates adds helper functions that let you modify the image containers as well as functions that generate images suitable for display. The generated functions are fully documented and have proper typespecs.
Saving new images
To create a new image from a Plug.Upload
, pass it in the image argument to one of the generated put functions.
The image will be saved to backend storage during the attached model's update.
for example
def save_avatar(%User{} = user, %Plug.Upload{} = image) do
user
|> User.changeset(%{})
|> User.put_image(:avatar, image)
|> Repo.update()
end
If the function completes correctly, the image will be persisted in the configured storage.
Deleting old images
Old images must be deleted after the transaction completes, as we can't be guaranteed that the model will be saved correctly. To delete old images, use an Ecto.Multi
def replace_avatar(%User{} = user, %Plug.Upload{} = avatar) do
old_image = User.find_image(user, :avatar)
changeset = user
|> User.changeset(%{})
|> User.put_image(:avatar, avatar)
Multi.new()
|> Multi.update(:update_user, changeset)
|> Multi.run(:delete_old_image, fn _, _ ->
case Eakins.Storage.delete(user, old_image) do
:ok -> {:ok, old_image}
error -> error
end)
|> Repo.transaction()
|> case do
{:ok, %{update_user: user}} ->
{:ok, user}
{: error, _failed_op, failed_value, _} ->
{:error, failed_value}
end