使用Ecto一次插入多行."协议可枚举的#Ecto.Changeset未实现"

Ale*_*edt 3 elixir ecto phoenix-framework

我有两张桌子.的表格topics其中has_many tweets.我的表tweets belongs_totopic.

主题架构:

defmodule Sentiment.Topic do
  use Sentiment.Web, :model

  schema "topics" do
    field :title, :string

    has_many :tweets, Sentiment.Tweet
  end

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:title])
    |> validate_required([:title])
  end
end
Run Code Online (Sandbox Code Playgroud)

推文架构:

defmodule Sentiment.Tweet do
  use Sentiment.Web, :model

  schema "tweets" do
    field :message, :string
    belongs_to :topic, Sentiment.Topic

  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:message])
    |> validate_required([:message])
  end
end
Run Code Online (Sandbox Code Playgroud)

我试图在topic我的表中插入一个,然后tweets在我对该主题进行推特搜索之后输入500 .

在我的控制器中,我用来Ecto.Multi对我的repo操作进行分组,但是,每次运行我的操作时都会出错protocol Enumerable not implemented for #Ecto.Changeset<action: nil, changes: %{message: "\"aloh....

这就是我试图首先插入我的主题,获取它的id,然后在一个事务中插入带有相关id的推文消息.

 def create(conn, %{"topic" => topic}) do
    # create a topic changeset
    topic_changeset = Topic.changeset(%Topic{}, topic)

    # obtain a list of tweet messages: ["hello", "a tweet", "sup!"]
    %{"title" => title} = topic
    all_tweets = title
    |> Twitter.search

# create an Ecto.Multi struct.
multi =
  Ecto.Multi.new
  |> Ecto.Multi.insert(:topics, topic_changeset) #insert topic
  |> Ecto.Multi.run(:tweets, fn %{topics: topic} ->
    changeset_tweets = all_tweets
    |> Enum.map(fn(tweet) ->
      %{topic_id: topic.id, message: tweet}
    end)

    Repo.insert_all(Tweet, changeset_tweets)

  end)

      # Run the transaction
      case Repo.transaction(multi) do # ERROR HERE!
        {:ok, result} ->
          conn
          |> put_flash(:info, "Success!")
          |> redirect(to: topic_path(conn, :index))
        {:error, :topics, topic_changeset, %{}} ->
          conn
          |> put_flash(:error, "Uh oh...")
          |> render("new.html", changeset: topic_changeset)
        {:error, :tweets, topic_changeset, %{}} ->
          conn
          |> put_flash(:error, "Something really bad happened...")
          |>render("new.html", changeset: topic_changeset)
      end
  end
Run Code Online (Sandbox Code Playgroud)

如何insert_all使用Ecto.Multi在一个事务中约500行?

更新 我已将更改集列表转换为地图列表,我的错误已更改为更令人困惑的内容.

错误 我试图插入什么

Paw*_*zak 9

对于Ecto.Multi正常使用工序进度,他们每个人都必须返回要么{:ok, value}{:error, reason}元组.

insert荷兰国际集团,update荷兰国际集团和delete荷兰国际集团变更集,它会自动返回这样一个元组,但是run,你需要明确地返回.

请考虑以下事项:

Ecto.Multi.new
|> Ecto.Multi.insert(:topics, topic_changeset) #insert topic
|> Ecto.Multi.run(:tweets, fn %{topics: topic} ->
   maps = 
     Enum.map(all_tweets, fn(tweet) ->
       %{topic_id: topic.id, message: tweet}
     end)

    {count, _} = Repo.insert_all(Tweet, maps)
    {:ok, count} # <----
end)
Run Code Online (Sandbox Code Playgroud)

  • Ecto.Multi可用于任何Elixir项目.这不一定是凤凰城.只是说!很高兴你发现它很有用! (2认同)