Giter Club home page Giter Club logo

Comments (13)

stavro avatar stavro commented on August 29, 2024 9
  1. Remove :photo from your cast call. It should not be present on cast, just cast_attachments.
  2. You will not be able to use scope.id during model creation, because your model will not have an id yet. You will either have to wait until the post is created, and then follow up with a subsequent call to cast_attachments, or you use some sort of uuid pattern.

from arc_ecto.

iamwilhelm avatar iamwilhelm commented on August 29, 2024 8

@stavro I have a question after reading the above thread. How do you make a subsequent call to cast_attachments? Can you provide an example? I'm trying to upload a file when the model is being created.

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

I think I just found my problem.

I was calling cast_attachments with the allowed as an atom.
cast_attachments(params, [:photo])

when walking over the method I seen this.

pry(2)> Arc.Ecto.Schema.convert_params_to_binary(params)
%{"body" => "adsf", "draft" => "false", "excerpt" => "asdf",
  "photo" => %Plug.Upload{content_type: "image/jpeg", filename: "test.jpg",
   path: "/var/folders/tj/nrvjcskx27ngvqy58x545_2h0000gn/T//plug-1467/multipart-941212-44262-1"},
  "published_at" => %{"day" => "20", "hour" => "0", "minute" => "0",
    "month" => "1", "year" => "2011"}, "slug" => "20", "title" => "20"}
pry(3)> Arc.Ecto.Schema.convert_params_to_binary(params) |> Dict.take([:photo])
%{}     
pry(4)> Arc.Ecto.Schema.convert_params_to_binary(params) |> Dict.take(["photo"])
%{"photo" => %Plug.Upload{content_type: "image/jpeg", filename: "test.jpg",
   path: "/var/folders/tj/nrvjcskx27ngvqy58x545_2h0000gn/T//plug-1467/multipart-941212-44262-1"}}

So it looks like the assignment of arc_params fails at Dict.take(allowed) cause the params has the key as a string.

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

Something else I'm seeing that is very odd to me is that in
arc_ecto/lib/arc_ecto/type.ex cast method where definition.store(args) is called both
store(definition, {file, scope}) when is_binary(file) or is_map(file) and store(definition, filepath) when is_binary(filepath) or is_map(filepath) are invoked.
That plus in the case of store(definition, {file, scope}) scope is still nil.

from arc_ecto.

stavro avatar stavro commented on August 29, 2024

What version of arc_ecto are you using? Dict.take should never have atoms, because it converts atoms to strings.

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

@stavro you are correct, sorry I missed that. I was having issue debugging and tried to run the code by hand. That being said I can confirm both that cast methods are indeed being called at the same time.

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

Well this is embarrassing. It looks as if I was using arc 0.1 and arc_ecto 0.1
I'v updated both and still observe the same error

[error] Task #PID<0.415.0> started from #PID<0.410.0> terminating
** (UndefinedFunctionError) function nil.id/0 is undefined (module nil is not available)
    nil.id()
    (digitalcakes) Digitalcakes.Imagable.storage_dir/2
    lib/arc/storage/s3.ex:5: Arc.Storage.S3.put/3
    (elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: #Function<0.62704849/0 in Arc.Actions.Store.async_put_version/3>
    Args: []
[error] Ranch protocol #PID<0.410.0> (:cowboy_protocol) of listener Digitalcakes.Endpoint.HTTP terminated
** (exit) an exception was raised:
    ** (UndefinedFunctionError) function nil.id/0 is undefined or private
        nil.id()
        (digitalcakes) Digitalcakes.Imagable.storage_dir/2
        lib/arc/storage/s3.ex:5: Arc.Storage.S3.put/3
        (elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
        (elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
        (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

from arc_ecto.

stavro avatar stavro commented on August 29, 2024

Can you add the actual controller and changeset code? I don't have enough information to help you right now

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

@stavro https://gist.github.com/digitalcake/232a730f6bb1bd6ecae81dca1cc919b5

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

Thank you for taking the time out and helping me.

from arc_ecto.

stavro avatar stavro commented on August 29, 2024

Of course! If that doesn't work ping me in irc @stavro and I'll make sure you're situated. 👋

from arc_ecto.

joshchernoff avatar joshchernoff commented on August 29, 2024

that was it, cast was also trying to invoke the uploader too which failed to set the scope correctly.

from arc_ecto.

ndarilek avatar ndarilek commented on August 29, 2024

Hitting the exact same issue with Ecto 3.2, and I think something significant has changed. In particular, I have to include my attachment field in cast, otherwise none of the Arc functions seem to be hit.

I have a slightly odd situation in that I'm trying to import a document either from a URL or a file. Users can enter a URL into a text field or upload a file. For now I'm focusing on the URL use case. Here are some snippets from my model/controller:

defmodule Scribe.Documents.Document do
  use Ecto.Schema
  use Arc.Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "documents" do
    field :name, :string
    field :original_url, EctoFields.URL
...
    field :original, ScribeWeb.Document.Type
...
  end

  def changeset(document, params \\ %{}) do
    IO.inspect(params)
    document
    |> cast(params, [:name, :original_url, :storage_upload_url, :input_format, :input_password, :is_input_password_needed, :input_page_count, :input_storage_key, :upload_file_name, :is_pdf_with_text, :input_processing_expected_page_count, :input_processing_completed_page_count])
    |> cast_attachments(params, [:original])
  end
end

defmodule ScribeWeb.DocumentController do
  use ScribeWeb, :controller
  plug :requires_auth, except: [:show]

...
  def create(conn, %{"document" => %{"original_url" => original_url} = document_params}) do
    user = conn.assigns[:current_user]
    case Documents.create_document(user, document_params) do
      {:ok, document} ->
        if document.original_url do
          {:ok, document} = Documents.update_document(document, %{"original" => original_url})
        end
        conn
        |> put_flash(:info, "Importing document...")
        |> redirect(to: Routes.document_path(conn, :show, document, "html"))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end
...
end

defmodule ScribeWeb.Document do
  use Arc.Definition
  # Include ecto support:
  use Arc.Ecto.Definition

...
  # Override the storage directory:
  def storage_dir(_version, {_file, scope}) do
    IO.puts("Here")
    "#{scope.id}"
  end
...
end

With this code, the IO.puts in storage_dir never executes, even though the IO.puts in changeset shows that I'm calling it with original. If I add :original to the cast call, it does print, but then I experience the error in this issue, even though I defer setting :original until after the model is inserted.

Would really appreciate some help here, even if it's only to advise me to switch to something else. Given the warnings I get with Ecto 3.2, I'm worried that something has changed and that this library is now incompatible, but I've been out of Elixir/Phoenix for a few years and am not sure what current solutions exist for file storage.

Thanks.

from arc_ecto.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.