凤凰,上传图片,控制器

时间:2016-09-05 20:29:20

标签: elixir phoenix-framework elixir-framework

我开始研究凤凰,试图将图像附加到亚马逊s3上的帖子和负载上。制作模型,使用这篇文章http://learningelixir.joekain.com/elixir-arc-with-a-single-module/,制作控制器。提交表单时收到错误:

[info] POST /posts
[debug] Processing by Blog.PostController.create/2
  Parameters: %{"_csrf_token" => "DkM9WAdYfxQ/dS0qQjU/FBILIic+NgAAaqE2D6FDOMICwTlVGaxnUQ==", "_utf8" => "✓", "post" => %{"body" => "789", "image" => %Plug.Upload{content_type: "image/jpeg", filename: "basilico.jpg", path: "/tmp/plug-1473/multipart-108288-12435-6"}, "title" => "6363"}}
  Pipelines: [:browser]
[debug] QUERY OK db=0.0ms
begin []
[debug] QUERY OK db=0.3ms
INSERT INTO "posts" ("body","title","user_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["789", "6363", 5, {{2016, 9, 5}, {20, 44, 48, 0}}, {{2016, 9, 5}, {20, 44, 48, 0}}]
[debug] QUERY OK db=123.3ms
commit []
[info] Sent 400 in 130ms
[debug] ** (Ecto.CastError) expected params to be a map, got: `%Plug.Upload{content_type: "image/jpeg", filename: "basilico.jpg", path: "/tmp/plug-1473/multipart-108288-12435-6"}`
    (ecto) lib/ecto/changeset.ex:343: Ecto.Changeset.do_cast/4
    (blog) web/models/image.ex:19: Blog.Image.changeset/2
    (blog) web/controllers/post_controller.ex:28: Blog.PostController.create/2
    (blog) web/controllers/post_controller.ex:1: Blog.PostController.action/2
    (blog) web/controllers/post_controller.ex:1: Blog.PostController.phoenix_controller_pipeline/2
    (blog) lib/blog/endpoint.ex:1: Blog.Endpoint.instrument/4
    (blog) lib/phoenix/router.ex:261: Blog.Router.dispatch/2
    (blog) web/router.ex:1: Blog.Router.do_call/2
    (blog) lib/blog/endpoint.ex:1: Blog.Endpoint.phoenix_pipeline/1
    (blog) lib/plug/debugger.ex:122: Blog.Endpoint."call (overridable 3)"/2
    (blog) lib/blog/endpoint.ex:1: Blog.Endpoint.call/2
    (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
    (cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

我的post.ex

defmodule Blog.Post do
  use Blog.Web, :model

  schema "posts" do
    field :title, :string
    field :body, :string
    has_one :image, Blog.Image
    belongs_to :user, Blog.User

    timestamps()
  end

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:title, :body, :user_id])
    |> validate_required([:title, :body, :user_id])
  end
end

my image.ex:

defmodule Blog.Image do
  use Blog.Web, :model

  alias Blog.Uploaders

  schema "images" do
    field :name, :string
    field :upload, :any, virtual: true
    belongs_to :post, Blog.Post

    timestamps
  end

  @required_fields ~w(name)
  @optional_fields ~w()

  def changeset(model, params \\ %{}) do
    model
    |> cast(params, ~w(upload), [])
    |> put_name
    |> cast(params, @required_fields, @optional_fields)
  end

  def put_name(changeset) do
    case changeset do
      %Ecto.Changeset{
        valid?: true,
        changes: %{upload: %Plug.Upload{content_type: "image/" <> _, filename: name}}
      } ->
        put_change(changeset, :name, name)
      _ ->
        changeset
    end
  end

  def store(%Plug.Upload{} = upload, image) do
    Uploaders.PostImage.store({upload, image})
  end

  def url(image, version) do
    Uploaders.PostImage.url({image.name, image}, version)
  end
end

my uploaders / post_image.ex:

defmodule Blog.Uploaders.PostImage do
  use Arc.Definition

  @acl :public_read
  @versions [:original, :show, :thumb]

  @heights %{
    show: 315,
    thumb: 30
  }

  def validate({file, _}) do
    ~w(.jpg .jpeg .gif .png) |> Enum.member?(Path.extname(file.file_name))
  end

  def transform(:thumb, _file) do
    {:convert, "-thumbnail x#{@heights[:thumb]} -gravity center -format jpg"}
  end
  def transform(:show, _file) do
    {:convert, "-strip -resize x#{@heights[:show]} -gravity center -format png"}
  end

  def storage_dir(version, {_, image}) do
    "uploads/posts/#{image.post_id}/images/#{image.id}/#{version}"
  end

  def filename(_version, {file, _}) do
    Path.rootname(file.file_name)
  end
end

和我的post_controller.ex:

  def create(conn, %{"post" => post_params}) do
    user = Addict.Helper.current_user(conn)
    # user = Blog.Repo.get(Blog.User, user.id)
    changeset = Blog.Post.changeset(%Blog.Post{}, Map.put(post_params, "user_id", user.id))
    case Blog.Repo.insert(changeset) do
      {:ok, post} ->
        image_params = Blog.Image.changeset(%Blog.Image{}, post_params["image"])
        image = Ecto.Model.build_assoc(post, :image, image_params)
        Blog.Repo.insert!(image)
        conn
        |> put_flash(:info, "Post created successfully.")
        |> redirect(to: post_path(conn, :show, post))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

问题:如何修复此错误?即使我应该尝试创建一个图像?

1 个答案:

答案 0 :(得分:0)

Blog.Image

  • schema定义应包含upload类型的字段Blog.Uploaders.PostImage.Type

schema "images" do field :upload, Blog.Uploaders.PostImage.Type ... end

  • 变更集应为cast_attachments
  • 致电upload

def changeset(model, params \\ %{}) do model # NOTE: don't include upload here, or it will be processed twice |> cast(params, ~w(name), []) |> put_name |> cast_attachments(params, [:upload]) end

希望这有帮助。