defmodule App.Newsletters.Newsletter do
use App.Schema
import Ecto.Changeset
schema "newsletters" do
field :frequency, :string
field :name, :string
field :sender_name, :string
field :email, :string
field :selected?, :boolean, virtual: true, default: false
timestamps()
end
@doc false
def changeset(newsletter, attrs) do
newsletter
|> cast(attrs, [:name, :frequency, :sender_name])
|> validate_required([:name, :frequency, :sender_name])
end
end
defmodule App.Digests.Digest do
use App.Schema
import Ecto.Changeset
schema "digests" do
field :frequency, :string
field :name, :string
belongs_to :organization, App.Organizations.Organization
many_to_many(
:newsletters,
App.Newsletters.Newsletter,
join_through: App.Digests.DigestsNewsletter,
on_replace: :delete,
join_keys: [digest_id: :id, newsletter_id: :id]
)
timestamps()
end
def for_id(query \\ __MODULE__, id) do
query
|> where([s], s.id == ^id)
end
@doc false
def changeset(digest, attrs) do
digest
|> cast(attrs, [:name, :frequency])
|> validate_required([:name, :frequency])
end
end
defmodule App.Digests.DigestsNewsletter do
@moduledoc """
UserProject module
"""
use App.Schema
import Ecto.Changeset
alias App.Digests.Digest
alias App.Newsletters.Newsletter
@already_exists "ALREADY_EXISTS"
@primary_key false
schema "newsletters_digests" do
belongs_to(:digest, Digest, primary_key: true)
belongs_to(:newsletter, Newsletter, primary_key: true)
timestamps()
end
@required_fields ~w(newsletter_id user_id)a
def changeset(newsletters_digests, params \\ %{}) do
newsletters_digests
|> cast(params, @required_fields)
|> validate_required(@required_fields)
|> foreign_key_constraint(:digest_id)
|> foreign_key_constraint(:newsletter_id)
|> unique_constraint([:digest, :newsletter],
name: :digest_id_newsletter_id_unique_index,
message: @already_exists
)
end
end
## Many to Many Migration
defmodule App.Repo.Migrations.CreateUserNewsletters do
use Ecto.Migration
def change do
create table(:newsletters_digests, primary_key: false) do
add(:digest_id, references(:digests, on_delete: :delete_all), primary_key: true)
add(:newsletter_id, references(:newsletters, on_delete: :delete_all), primary_key: true)
timestamps()
end
create(index(:newsletters_digests, [:digest_id]))
create(index(:newsletters_digests, [:newsletter_id]))
create(
unique_index(:newsletters_digests, [:digest_id, :newsletter_id],
name: :digest_id_newsletter_id_unique_index
)
)
end
end
I have a many to many field that connects newsletters and digests. When I try to preload the many to many field newsletters via
Repo.get!(Digest, id)
|> Repo.preload(:newsletters)
I get the following error
[error] #PID<0.898.0> running AppWeb.Endpoint (connection #PID<0.880.0>, stream id 3) terminated
Server: localhost:4000 (http)
Request: GET /app/digest_live/mvMl2V
** (exit) an exception was raised:
** (Postgrex.Error) ERROR 42704 (undefined_object) type "serial" does not exist
query: SELECT n0."id", n0."frequency", n0."name", n0."sender_name", n0."email", n0."inserted_at", n0."updated_at", n1."digest_id"::serial FROM "newsletters" AS n0 INNER JOIN "newsletters_digests" AS n1 ON n0."id" = n1."newsletter_id" WHERE (n1."digest_id" = ANY($1)) ORDER BY n1."digest_id"::serial
(ecto_sql 3.8.0) lib/ecto/adapters/sql.ex:928: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.8.0) lib/ecto/adapters/sql.ex:843: Ecto.Adapters.SQL.execute/6
(ecto 3.8.1) lib/ecto/repo/queryable.ex:221: Ecto.Repo.Queryable.execute/4
(ecto 3.8.1) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(elixir 1.13.3) lib/enum.ex:1593: Enum."-map/2-lists^map/1-0-"/2
(app 0.1.0) lib/app_web/live/digest_live.ex:23: AppWeb.DigestLive.apply_action/3
(app 0.1.0) lib/app_web/live/digest_live.ex:19: AppWeb.DigestLive.handle_params/3
(phoenix_live_view 0.17.6) lib/phoenix_live_view/utils.ex:369: anonymous fn/5 in Phoenix.LiveView.Utils.call_handle_params!/5
(telemetry 1.1.0) /Users/shapathneupane/Developer/boilerplate_1.6/synopsis/deps/telemetry/src/telemetry.erl:320: :telemetry.span/3
(phoenix_live_view 0.17.6) lib/phoenix_live_view/static.ex:271: Phoenix.LiveView.Static.call_mount_and_handle_params!/5
(phoenix_live_view 0.17.6) lib/phoenix_live_view/static.ex:110: Phoenix.LiveView.Static.render/3
(phoenix_live_view 0.17.6) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
(phoenix 1.6.6) lib/phoenix/router.ex:355: Phoenix.Router.__call__/2
(app 0.1.0) lib/app_web/endpoint.ex:1: AppWeb.Endpoint.plug_builder_call/2
(app 0.1.0) lib/plug/debugger.ex:136: AppWeb.Endpoint."call (overridable 3)"/2
(app 0.1.0) lib/app_web/endpoint.ex:1: AppWeb.Endpoint.call/2
However, when I try to preload :organization in the digest schema. It works and preloads the organization.
# this preloads organization without errors
Repo.get!(Digest, id)
|> Repo.preload(:organiaztion)
%App.Digests.Digest{
__meta__: #Ecto.Schema.Metadata<:loaded, "digests">,
frequency: "ONCE",
id: "mvMl2V",
inserted_at: ~U[2022-04-28 14:15:16Z],
name: "ANOTHER DATASET",
newsletters: #Ecto.Association.NotLoaded<association :newsletters is not loaded>,
organization: %App.Organizations.Organization{
__meta__: #Ecto.Schema.Metadata<:loaded, "organizations">,
active: true,
domain: nil,
email: nil,
id: 1,
inserted_at: ~U[2022-04-28 03:01:21Z],
},
organization_id: "gKg12n",
updated_at: ~U[2022-04-28 14:15:16Z]
}
Is there any changes to be made for many_to_many
association preload?