如何使用elixir/phoenix从csv文件导入用户? [英] How to import users from csv file with elixir/phoenix?

查看:120
本文介绍了如何使用elixir/phoenix从csv文件导入用户?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在UserController中有一个包含用户列表和以下导入方法的csv文件,我想通过使用表单提交csv文件来导入这些用户.而且看来我做错了.

I have a csv file with a list of users and the following import method inside UserController and I would like to import these users by submitting the csv file with a form. And It looks like I'm doing it wrong.

users_controller

  def import(conn, %{"user" => user_params}) do
    user_params["file"]
    |> File.stream!()
    |> CSV.decode
    |> Enum.each(fn(user) -> User.changeset(%User{}, %{name: Enum.at(user, 0), email: Enum.at(user, 1)}) |> Repo.insert end)
    conn
    |> put_flash(:info, "Imported")
    |> redirect(to: user_path(conn, :index))
  end

路线

post "/import", UsersController, :import, as: :import_csv

表格

<%= render "import_form.html", changeset: @changeset,
                        action: import_csv_path(@conn, :import) %>

-

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

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

模型

  schema "users" do
    field :name, :string
    field :email, :string
    field :file, :any, virtual: true
    timestamps()
  end

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :email, :file])
    |> validate_required([:name, :email])
    |> unique_constraint(:email)
  end


以下代码适用于iex

  def import(file) do
    file
    |> File.stream!()
    |> CSV.decode
    |> Enum.each(fn(user) -> User.changeset(%User{}, %{name: Enum.at(user, 0), email: Enum.at(user, 1)}) |> Repo.insert end)
  end

推荐答案

您不会在参数中找到文件.这是我得到的用于多部分文件的参数

You don't get a file back in your params. Here are the params I get back for a multipart file

[warn] module=UcxChat.AttachmentController line=10 function=create/2  attachment params: %{"channel_id" => "300233dd-782f-4718-9eed-00b8cc412a79", "description" => "", "file" => %Plug.Upload{content_type: "text/plain", filename: "test.txt", path: "/var/folders/wt/3q11kty15rqfb5v9rpqg0ssm0000gn/T//plug-1494/multipart-421483-239132-3"}, "file_name" => "test.txt", "type" => "text/plain", "user_id" => "427452eb-c9cf-457b-9c55-0904c9d24385"}

您可以看到params["file"]Plug.upload结构.

要获取实际文件,应获取:path字段,例如:

To get the actual file, you should get the :path field like:

  def import(conn, %{"user" => user_params}) do
    user_params["file"].path
    |> File.stream!()
    |> CSV.decode
    |> Enum.each(fn(user) -> User.changeset(%User{}, %{name: Enum.at(user, 0), email: Enum.at(user, 1)}) |> Repo.insert end)
    conn
    |> put_flash(:info, "Imported")
    |> redirect(to: user_path(conn, :index))
  end

您可能还想进行一些错误处理.像这样:

You probably also want to do some error handling. Something like:

def import(conn, %{"user" => user_params}) do
  user_params["file"].path
  |> File.stream!()
  |> CSV.decode
  |> Enum.map(fn(user) -> 
    User.changeset(%User{}, %{name: Enum.at(user, 0), email: Enum.at(user, 1)}) |> Repo.insert 
  end)
  |> Enum.filter(fn 
    {:error, cs} -> true
    _ -> false
  end)
  |> case do
    [] -> 
      conn
      |> put_flash(:info, "Imported")
      |> redirect(to: user_path(conn, :index))
    errors -> 
      errors = parse_errors(errors)  # create this fun 
      conn
      |> put_flash(:erorr, errors)
      |> render("import.html")
  end
end

这篇关于如何使用elixir/phoenix从csv文件导入用户?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆