Reputation: 16761
I'm using elixirs Arc with Ecto and Amazon S3 to store files that I have previously downloaded. Everything seems to work, they end up on S3. But nothing is stored in my database. So if I try to generate an URL I always just get the default url back.
This is how I store a file:
iex > user = Repo.get(User, 3)
iex > Avatar.store({"/tmp/my_file.png", user})
{:ok, "my_file.png"}
But the user.avatar
field is still nil.
My user module:
defmodule MyApp.User do
use MyApp.Web, :model
use Arc.Ecto.Schema
alias MyApp.Repo
schema "users" do
field :name, :string
field :email, :string
field :avatar, MyApp.Avatar.Type
embeds_many :billing_emails, MyApp.BillingEmail
embeds_many :addresses, MyApp.Address
timestamps
end
@required_fields ~w(name email)
@optional_fields ~w(avatar)
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_embed(:billing_emails)
|> cast_embed(:addresses)
|> validate_required([:name, :email])
|> validate_format(:email, ~r/@/)
|> unique_constraint(:email)
|> cast_attachments(params, [:avatar])
end
end
The Avatar uploader:
defmodule MyApp.Avatar do
use Arc.Definition
# Include ecto support (requires package arc_ecto installed):
use Arc.Ecto.Definition
@acl :public_read
# To add a thumbnail version:
@versions [:original, :thumb]
# Whitelist file extensions:
def validate({file, _}) do
~w(.jpg .jpeg .gif .png) |> Enum.member?(Path.extname(file.file_name))
end
# Define a thumbnail transformation:
def transform(:thumb, _) do
{:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
end
def transform(:original, _) do
{:convert, "-format png", :png}
end
def filename(version, {file, scope}), do: "#{version}-#{file.file_name}"
# Override the storage directory:
def storage_dir(version, {file, scope}) do
"uploads/user/avatars/#{scope.id}"
end
# Provide a default URL if there hasn't been a file uploaded
def default_url(version, scope) do
"/images/avatars/default_#{version}.png"
end
end
Upvotes: 0
Views: 1379
Reputation: 16761
So the answer to this is twofold. First of all I had to remove avatar
from my optional_fields
in my User Module.
@optional_fields ~w()
Second you don't call Avatar.store
directly but use a changeset.
avatar_params = %{avatar: "/tmp/my_file.jpg"}
user = Repo.get(User, 1)
avatar_changeset = User.changeset(user, avatar_params)
Repo.update(avatar_changeset)
Edit: In a more Elixir way:
avatar_params = %{avatar: "/tmp/my_file.jpg"}
Repo.get(User, 1) |> User.changeset(avatar_params) |> Repo.update()
Upvotes: 2