将数据插入关联(?)

时间:2017-03-17 20:35:42

标签: elixir phoenix-framework

我试图在凤凰城设置一个基本数据库,并且想要一个类似于Phoenix Ecto tutorialVideo模型的模型 - 基本上使用has_many - 以及与File Uploads tutorial类似的上传。

在我的情况下,我希望允许用户上传多个.csv,这些已添加到数据库中。现在我限制一个.csv上传创建一个用户专注于让那么多工作。我也不关心我将要存储的内容 - 现在是.csv所在的路径,只是为了简单起见。将来我可能想直接存储csv数据。

我在user_params中获取%Plug.Upload,并且能够将其写入文件,但我不确定如何将该路径添加到数据库中。

最新错误发生在用户/模型中(见下文)。

这是我到目前为止所拥有的:

模型/ csv.ex

defmodule Test.CSV do
  use Test.Web, :model

  schema "csvs" do
    field :csv, {:array, :string}
    belongs_to :user, Test.User

    timestamps()
  end
  ...

模型/ user.ex

defmodule Test.User do
  use Test.Web, :model

  schema "users" do
    field :uname, :string
    field :group, :string

    has_many :csvs, Test.CSV
    timestamps()
  end
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:uname, :group])
    # Wasn't sure what else to do here. Currently throws an error at this line with 'protocol Enumerable not implemented for %Plug.Upload{...filename...etc.}'. 
    # I figure I probably need to specify somewhere that I only want a certain field, like the path, but I'm not sure how to do that.
    |> cast_assoc([:csvs])
    |> validate_required([:uname, :group])
  end

user_controller.ex

...
def create(conn, %{"user" => user_params}) do
  changeset = User.changeset(%User{}, user_params)

  case Repo.insert(changeset) do
    {:ok, _user} ->
      conn
      |> put_flash(:info, "User created successfully.")
      |> redirect(to: user_path(conn, :index))
    {:error, changeset} ->
      render(conn, "new.html", changeset: changeset)
  end
end
...

用户/ forms.html.eex

<%= form_for @changeset, @action, [multipart: true], fn f -> %>
...
<%= inputs_for f, :csvs, fn i -> %>
  <div class="form-group">
  <label>CSV</label>
  <%= file_input i, :csv, class: "form-control" %>
  </div>
<% end %>
...
<% end %>

我还确保我做了ecto.migrate并将csvs表添加到数据库中。

def change do
  alter table(:users) do
    # Hmm, not sure if that should have been a :map.
    add :csvs, :map
  end
end

然后我是否应该使用嵌套关联(正确的术语?),或者使用嵌入式模式的路径。毋庸置疑,我是凤凰城的新手,非常感谢有关如何解决这个问题的任何想法。谢谢!

1 个答案:

答案 0 :(得分:0)

我真的很惊讶你是如何在模式{:array, :string}中使用这种表示法的...对你的案例最简单的解决方案是在has_many之间建立User关系和CSV这部分你有效。

现在由您决定如何在数据库中存储有关这些CSV的信息 - 如果您处理Plug.Upload它只不过是文件,但您需要自定义Ecto的方式使用Ecto.Type处理此类型,因为file是一个复杂的结构。

另一种选择是解析该CSV文件,然后将其放入CSV表并将其与User关联,可能最好的方法是使用CSV插件读取内容文件 - CSVLixir或任何其他文件 - 并将其与put_assoc合并。

就我个人而言,我不会在数据库中存储整个文件,但会引用它,例如。文件名和内容(如果需要)。