协议可枚举未实现 {:ok, ["Massimo Dutti", "Sneakers laag", "38", "Black", "99.95"]} 类型元组

问题描述

对于学校项目,我们必须在 elixir 中创建一个可以通过上传 csv 文件来创建新产品的网上商店。我们尝试通过遵循 How to import users from csv file with elixir/phoenix? 来实现这一点,但我们总是得到一个错误(见标题
有人可以帮助我们吗?这是我们的代码
表格

<%= form_for @changeset,@action,[multipart: true],fn f -> %>
 <div class="form-group">
  <label>File</label>
  <%= file_input f,:file,class: "form-control" %>
 </div>

 <div class="form-group">
  <%= submit "Submit",class: "btn btn-primary" %>
 </div>
<% end %>

渲染

<%= render "bulkform.html",changeset: @changeset,action: Routes.product_path(@conn,:createBulk) %>

路线

post "/productsBulk",ProductController,:createBulk

架构

schema "products" do
 field :color,:string
 field :size,:string
 field :description,:string
 field :price,:decimal
 field :title,:string

 timestamps()
end

@doc false
def changeset(product,attrs) do
product
 |> cast(attrs,[:title,:description,:size,:color,:price,:stock])
 |> validate_required([:title,:stock])
 |> unique_constraint(:title,name: :unique_products_index,message:
 "Title already in use.")
end

控制器

def createBulk(conn,%{"product" => product_params}) do
 product_params["file"].path
 |> File.stream!()
 |> CSV.decode
 |> Enum.each(fn(product) -> Product.changeset(%Product{},%{title: Enum.at(product,0),description: 
 Enum.at(product,1),size: Enum.at(product,2),color: Enum.at(product,3),price: Enum.at(product,4)})
 |> Repo.insert() end)
 conn
 |> put_flash(:info,"Imported")
 |> redirect(to: Routes.product_path(conn,:overview))
end

解决方法

如果您完整地包含错误消息,并且您能准确地向我们显示错误消息中提到的行,那将会更有帮助。

但是,正如 Aleksei 已经指出的那样,我怀疑您的问题是您将 元组 传递给 Enum.each/1,而您应该传递一个列表。换句话说:

Enum.each({:ok,[1,2,3]},fn x -> IO.puts(x) end)
** (Protocol.UndefinedError) protocol Enumerable not implemented for ...

虽然这很好用:

Enum.each([1,3],fn x -> IO.puts(x) end)

因此 CSV.decode 的输出不能直接传送到 Enum 函数中,因为它返回一个元组,但使用 CSV.decode! 应该返回原始列表,您的代码应该可以工作。