问题描述
对于学校项目,我们必须在 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!
应该返回原始列表,您的代码应该可以工作。