create/2 中没有匹配的函数子句
no function clause matching in create/2
作为我 elixir/phoenix 学习曲线的一部分,我正在开发一个简单的在线商店。目前我正面临错误:no function clause matching in JordanivaWeb.ProductController.create/2
。我正在尝试使用 Arc 一次上传多个文件,当我提交表单时出现此错误。对于如何解决此问题的任何帮助或建议,我将不胜感激。
产品架构:
schema "products" do
field :colour, :string
field :description, :string
field :name, :string
field :price, :decimal
field :product_code, :string
field :release_year, :integer
belongs_to :category, Jordaniva.Categories.Category
belongs_to :subcategory, Jordaniva.Categories.Subcategory
belongs_to :type, Jordaniva.Inventory.Type
has_many :items, Jordaniva.Inventory.Item
has_many :photos, Jordaniva.Gallery.Photo
timestamps()
end
@doc false
def changeset(struct, attrs \ %{}) do
struct
|> cast(attrs, [:name, :description, :price, :colour, :product_code, :release_year, :category_id, :subcategory_id, :type_id])
|> cast_assoc(:items)
|> cast_assoc(:photos)
|> validate_required([:name, :description, :price, :colour, :product_code, :release_year, :category_id, :subcategory_id, :type_id])
end
照片架构
schema "photos" do
field :photo, Jordaniva.Photo.Type
field :uuid, :string
belongs_to :product, Jordaniva.Inventory.Product
timestamps()
end
@doc false
def changeset(image, attrs) do
image
|> Map.update(:uuid, Ecto.UUID.generate, fn val -> val || Ecto.UUID.generate end)
|> cast_attachments(attrs, [:photo])
|> validate_required([:photo])
产品负责人(new/create):
def new(conn, _params) do
changeset = Product.changeset(%Product{photos: [%Jordaniva.Gallery.Photo{}]})
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
def create(conn, %{"product" => product_params}) do
case Inventory.create_product(product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product created successfully.")
|> redirect(to: Routes.product_path(conn, :show, product))
{:error, %Ecto.Changeset{} = changeset} ->
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
end
请告知是否需要更多代码。提前致谢。
编辑:
错误跟踪
The following arguments were given to JordanivaWeb.ProductController.create/2:
# 1
%Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{types: [%Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 3, inserted_at: ~N[2020-08-12 10:46:24], name: "Kids", updated_at: ~N[2020-08-12 10:46:24]}, %Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 1, inserted_at: ~N[2020-08-12 10:46:24], name: "Men", updated_at: ~N[2020-08-12 10:46:24]}, %Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 2, inserted_at: ~N[2020-08-12 10:46:24], name: "Women", updated_at: ~N[2020-08-12 10:46:24]}]}, before_send: [#Function<0.73641281/1 in Plug.CSRFProtection.call/2>, #Function<2.102658996/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.105793137/1 in Plug.Session.before_send/2>, #Function<0.60895335/1 in Plug.Telemetry.call/2>, #Function<0.33293990/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], body_params: %{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}, cookies: %{"_jordaniva_key" => "SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, halted: false, host: "localhost", method: "POST", owner: #PID<0.1540.0>, params: %{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}, path_info: ["products"], path_params: %{}, port: 4000, private: %{JordanivaWeb.Router => {[], %{}}, :phoenix_action => :create, :phoenix_controller => JordanivaWeb.ProductController, :phoenix_endpoint => JordanivaWeb.Endpoint, :phoenix_flash => %{}, :phoenix_format => "html", :phoenix_layout => {JordanivaWeb.LayoutView, :app}, :phoenix_request_logger => {"request_logger", "request_logger"}, :phoenix_router => JordanivaWeb.Router, :phoenix_view => JordanivaWeb.ProductView, :plug_multipart => :done, :plug_session => %{"_csrf_token" => "TU8CAaejwzoX9xvIjfZaaOt3"}, :plug_session_fetch => :done}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{"_jordaniva_key" => "SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, req_headers: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate"}, {"accept-language", "pl,en-US;q=0.7,en;q=0.3"}, {"connection", "keep-alive"}, {"content-length", "3185491"}, {"content-type", "multipart/form-data; boundary=---------------------------18456436416963235192732034760"}, {"cookie", "_jordaniva_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, {"host", "localhost:4000"}, {"origin", "http://localhost:4000"}, {"referer", "http://localhost:4000/products/new"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0"}], request_path: "/products", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "Fiy9oT4ISHA2dMUAABjm"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-permitted-cross-domain-policies", "none"}, {"cross-origin-window-policy", "deny"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}
# 2
%{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}
编辑 2:
错误跟踪:
Protocol.UndefinedError at POST /products
protocol Enumerable not implemented for %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597863566-633102118642948-6"} of type Plug.Upload (a struct). This protocol is implemented for the following type(s): Ecto.Adapters.SQL.Stream, Postgrex.Stream, DBConnection.Stream, DBConnection.PrepareStream, HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
光控制器new/create:
def new(conn, _params) do
changeset = Gallery.change_photo(%Photo{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"product_id" => product_id, "photos" => photo_params}) do
product = Jordaniva.Inventory.get_product!(product_id)
with :ok <- Gallery.create_photos(photo_params) do
conn
|> put_flash(:info, "Upload successful.")
end
end
Inventory.ex
def create_product(attrs \ %{}) do
%Product{}
|> Product.changeset(attrs)
|> Repo.insert()
end
在gallery.ex
def create_photos(%Product{} = product, attrs \ %{}) do
Enum.each attrs["photos"], fn p ->
create_photo(product, %{"photo" => p})
end
end
create_photo 在 gallery.ex
def create_photo(%Product{} = product, attrs \ %{}) do
%Photo{}
|> Photo.changeset(attrs)
|> Ecto.Changeset.put_assoc(:product, product)
|> Repo.insert()
end
就像我在评论中建议的那样,发生错误是因为您的控制器接收到的参数与 %{"product" => ...}
不匹配,因为从错误消息中可以看出,没有 "product"
输入第二个参数。
也许你的意思是:
def create(conn, %{"photos" => product_params}) do
case Inventory.create_product(product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product created successfully.")
|> redirect(to: Routes.product_path(conn, :show, product))
{:error, %Ecto.Changeset{} = changeset} ->
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
end
因为params中包含的是"photos"
,其中包含category_id
、description
、photos
等
作为我 elixir/phoenix 学习曲线的一部分,我正在开发一个简单的在线商店。目前我正面临错误:no function clause matching in JordanivaWeb.ProductController.create/2
。我正在尝试使用 Arc 一次上传多个文件,当我提交表单时出现此错误。对于如何解决此问题的任何帮助或建议,我将不胜感激。
产品架构:
schema "products" do
field :colour, :string
field :description, :string
field :name, :string
field :price, :decimal
field :product_code, :string
field :release_year, :integer
belongs_to :category, Jordaniva.Categories.Category
belongs_to :subcategory, Jordaniva.Categories.Subcategory
belongs_to :type, Jordaniva.Inventory.Type
has_many :items, Jordaniva.Inventory.Item
has_many :photos, Jordaniva.Gallery.Photo
timestamps()
end
@doc false
def changeset(struct, attrs \ %{}) do
struct
|> cast(attrs, [:name, :description, :price, :colour, :product_code, :release_year, :category_id, :subcategory_id, :type_id])
|> cast_assoc(:items)
|> cast_assoc(:photos)
|> validate_required([:name, :description, :price, :colour, :product_code, :release_year, :category_id, :subcategory_id, :type_id])
end
照片架构
schema "photos" do
field :photo, Jordaniva.Photo.Type
field :uuid, :string
belongs_to :product, Jordaniva.Inventory.Product
timestamps()
end
@doc false
def changeset(image, attrs) do
image
|> Map.update(:uuid, Ecto.UUID.generate, fn val -> val || Ecto.UUID.generate end)
|> cast_attachments(attrs, [:photo])
|> validate_required([:photo])
产品负责人(new/create):
def new(conn, _params) do
changeset = Product.changeset(%Product{photos: [%Jordaniva.Gallery.Photo{}]})
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
def create(conn, %{"product" => product_params}) do
case Inventory.create_product(product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product created successfully.")
|> redirect(to: Routes.product_path(conn, :show, product))
{:error, %Ecto.Changeset{} = changeset} ->
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
end
请告知是否需要更多代码。提前致谢。
编辑: 错误跟踪
The following arguments were given to JordanivaWeb.ProductController.create/2:
# 1
%Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{types: [%Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 3, inserted_at: ~N[2020-08-12 10:46:24], name: "Kids", updated_at: ~N[2020-08-12 10:46:24]}, %Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 1, inserted_at: ~N[2020-08-12 10:46:24], name: "Men", updated_at: ~N[2020-08-12 10:46:24]}, %Jordaniva.Inventory.Type{__meta__: #Ecto.Schema.Metadata<:loaded, "types">, id: 2, inserted_at: ~N[2020-08-12 10:46:24], name: "Women", updated_at: ~N[2020-08-12 10:46:24]}]}, before_send: [#Function<0.73641281/1 in Plug.CSRFProtection.call/2>, #Function<2.102658996/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.105793137/1 in Plug.Session.before_send/2>, #Function<0.60895335/1 in Plug.Telemetry.call/2>, #Function<0.33293990/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], body_params: %{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}, cookies: %{"_jordaniva_key" => "SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, halted: false, host: "localhost", method: "POST", owner: #PID<0.1540.0>, params: %{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}, path_info: ["products"], path_params: %{}, port: 4000, private: %{JordanivaWeb.Router => {[], %{}}, :phoenix_action => :create, :phoenix_controller => JordanivaWeb.ProductController, :phoenix_endpoint => JordanivaWeb.Endpoint, :phoenix_flash => %{}, :phoenix_format => "html", :phoenix_layout => {JordanivaWeb.LayoutView, :app}, :phoenix_request_logger => {"request_logger", "request_logger"}, :phoenix_router => JordanivaWeb.Router, :phoenix_view => JordanivaWeb.ProductView, :plug_multipart => :done, :plug_session => %{"_csrf_token" => "TU8CAaejwzoX9xvIjfZaaOt3"}, :plug_session_fetch => :done}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{"_jordaniva_key" => "SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, req_headers: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate"}, {"accept-language", "pl,en-US;q=0.7,en;q=0.3"}, {"connection", "keep-alive"}, {"content-length", "3185491"}, {"content-type", "multipart/form-data; boundary=---------------------------18456436416963235192732034760"}, {"cookie", "_jordaniva_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYVFU4Q0FhZWp3em9YOXh2SWpmWmFhT3Qz.V_FNdlE0nFNXTTd8tO3FXvDggZ0D2el4KMQBf96dszI"}, {"host", "localhost:4000"}, {"origin", "http://localhost:4000"}, {"referer", "http://localhost:4000/products/new"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0"}], request_path: "/products", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "Fiy9oT4ISHA2dMUAABjm"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-permitted-cross-domain-policies", "none"}, {"cross-origin-window-policy", "deny"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}
# 2
%{"_csrf_token" => "YiRvKRImFSIaExVsYzpGFixSHgw4DS1K6qWjSGpHmiz4ZB0_F4DmYBYy", "photos" => %{"category_id" => "1", "colour" => "test11", "description" => "test11", "name" => "test11", "photos" => [%Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-293284844145788-6"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.13.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-307924305137465-2"}, %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.21.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597860468-503950842927652-2"}], "price" => "11111", "product_code" => "test11", "release_year" => "2000", "subcategory_id" => "1", "type_id" => "2"}}
编辑 2:
错误跟踪:
Protocol.UndefinedError at POST /products
protocol Enumerable not implemented for %Plug.Upload{content_type: "image/png", filename: "Zrzut ekranu 2020-07-20 o 22.46.06.png", path: "/var/folders/1t/q27498654m376jz6fl02fqd80000gn/T//plug-1597/multipart-1597863566-633102118642948-6"} of type Plug.Upload (a struct). This protocol is implemented for the following type(s): Ecto.Adapters.SQL.Stream, Postgrex.Stream, DBConnection.Stream, DBConnection.PrepareStream, HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
光控制器new/create:
def new(conn, _params) do
changeset = Gallery.change_photo(%Photo{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"product_id" => product_id, "photos" => photo_params}) do
product = Jordaniva.Inventory.get_product!(product_id)
with :ok <- Gallery.create_photos(photo_params) do
conn
|> put_flash(:info, "Upload successful.")
end
end
Inventory.ex
def create_product(attrs \ %{}) do
%Product{}
|> Product.changeset(attrs)
|> Repo.insert()
end
在gallery.ex
def create_photos(%Product{} = product, attrs \ %{}) do
Enum.each attrs["photos"], fn p ->
create_photo(product, %{"photo" => p})
end
end
create_photo 在 gallery.ex
def create_photo(%Product{} = product, attrs \ %{}) do
%Photo{}
|> Photo.changeset(attrs)
|> Ecto.Changeset.put_assoc(:product, product)
|> Repo.insert()
end
就像我在评论中建议的那样,发生错误是因为您的控制器接收到的参数与 %{"product" => ...}
不匹配,因为从错误消息中可以看出,没有 "product"
输入第二个参数。
也许你的意思是:
def create(conn, %{"photos" => product_params}) do
case Inventory.create_product(product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product created successfully.")
|> redirect(to: Routes.product_path(conn, :show, product))
{:error, %Ecto.Changeset{} = changeset} ->
categories = Repo.all(Category) |> Enum.map(&{&1.name, &1.id})
subcategories = Repo.all(Subcategory) |> Enum.map(&{&1.name, &1.id})
render(conn, "new.html", changeset: changeset, categories: categories, subcategories: subcategories)
end
end
因为params中包含的是"photos"
,其中包含category_id
、description
、photos
等