Reputation: 413
Im trying to attach multiple images to a field. I could easily create an association to a images model, but I would like to see how could the same be accomplished with a map/array field.
The model looks as follows.
schema "users" do
field :images, {:array}
end
def changeset(user, params \\ :invalid) do
user
|> cast(params, [:name])
|> cast_attachments(params, [:avatar])
|> validate_required([:name, :avatar])
end
Upvotes: 1
Views: 266
Reputation: 3663
As far as I know using an array/map directly is not supported.
You could use and embedded schema to save it as a map though.
This should work:
defmodule Image do
use Ecto.Schema
use Arc.Ecto.Schema
import Ecto
import Ecto.Changeset
@required_fields ~w(file)
@optional_fields ~w()
embedded_schema do
field :file, MyApp.UserImage.Type
end
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_attachments(params, [:file])
end
end
defmodule User do
use Ecto.Schema
import Ecto
import Ecto.Changeset
schema "projects" do
field :code, :string
embeds_many :images, MyApp.Image
end
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_embed(:images) # invoke changeset in the embed module
end
end
And then you can use it like this
images = [%{file: "image1"}, %{file: "image2"}]
changeset = User.changeset(user, %{"images" => images})
new_user = Repo.update!(changeset)
urls = Enum.map new_user.images, fn image ->
UserImage.urls({image.file, new_user})
end
The only drawback is that you can't use the scope
param in the UserImage
module anymore when saving the images. This is because arc_ecto uses the model as the scope
when you invoke cast_attachments function, and now you don't have the original model (User) when calling the function.
In the migration file you should define the images field to be a :map
Upvotes: 1