I have two tables. A table of topics
which has_many
tweets
. My table of tweets
belongs_to
a topic
.
Topic Schema:
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
Tweet Schema:
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
I am attempting to insert a topic
into my table, followed by 500 tweets
after I run a twitter search for that topic.
In my controller, I use Ecto.Multi
to group my repo operations, however, each time I run my operation I get an error protocol Enumerable not implemented for #Ecto.Changeset<action: nil, changes: %{message: "\"aloh....
This is how I am attempting to insert my topic first, obtain it's id, and then insert a tweet message with the associated id with one transaction.
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
How can I insert_all
about 500 rows in one transaction using Ecto.Multi?
Update I have converted the list of changesets into a list of maps and my error has changed to something even more confusing.
Repo.insert_all
since it only supports list of maps and lists of keyword lists, not list of changesets. – MedallistRepo.insert_all
. however, that function does not accept a list of changesets. It only takes a list of maps or a list of keyword lists. – Condescendingtopic_id
andmessage
. When I attempt to run the transaction, my error isno case clause matching: {5, nil}
– Watercast_assoc(:tweets)
in the topic changeset, instead of performing the same thing manually? – Isosteric