Hi ,
I am trying to save data from an appointment form in which there is a many-to-many relationship (one appointment can have many services and one service can have many appointments), in the appointment form I can select several services and I want to store the services selected in the database with the many-to-many relationship.
Here is my schema of the appointments:
defmodule MedussaStudio.Appointments.Appointment do
alias MedussaStudio.AppointmentsServices.AppointmentService
alias MedussaStudio.Accounts
use Ecto.Schema
import Ecto.Changeset
schema "appointments" do
field :date, :date
field :start_time, :time
field :end_time, :time
belongs_to :user, Accounts.User
many_to_many :appointment_services, MedussaStudio.Services.Service,
join_through: AppointmentService,
on_replace: :delete
timestamps(type: :utc_datetime)
end
@doc false
def changeset(appointment, attrs) do
appointment
|> cast(attrs, [:date, :start_time, :end_time, :user_id])
|> validate_required([:date, :start_time, :end_time])
end
end
Here is my schema of the services:
defmodule MedussaStudio.Services.Service do
alias MedussaStudio.AppointmentsServices.AppointmentService
use Ecto.Schema
import Ecto.Changeset
schema "services" do
field :name, :string
field :price, :decimal
many_to_many :appointment_services, MedussaStudio.Appointments.Appointment,
join_through: AppointmentService,
on_replace: :delete
timestamps(type: :utc_datetime)
end
@doc false
def changeset(service, attrs) do
service
|> cast(attrs, [:name, :price])
|> validate_required([:name, :price])
end
end
And here is the function of my live view that saves the appointments:
defp save_appointment(socket, :new, appointment_params) do
case Appointments.create_appointment(add_user_id_to_appointment(socket, appointment_params)) do
{:ok, appointment} ->
%{"services" => services} = appointment_params
id_services =
Enum.map(services, fn service ->
service |> String.to_integer() |> Services.get_service!()
end)
updated_appointment =
appointment
|> Repo.preload(:appointment_services)
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(
:appointment_services,
id_services
)
|> Repo.update()
case updated_appointment do
{:ok, appointment} ->
notify_parent({:saved, appointment})
{:noreply,
socket
|> put_flash(:info, "Cita creada exitosamente")
|> push_patch(to: socket.assigns.patch)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end
This is my schema of appointment services that saves the association:
defmodule MedussaStudio.AppointmentsServices.AppointmentService do
use Ecto.Schema
schema "appointments_services" do
belongs_to :service, MedussaStudio.Services.Service
belongs_to :appointment, MedussaStudio.Appointments.Appointment
timestamps()
end
end
And this is my error when i try to save the appointment with the appointment form data
[error] GenServer #PID<0.6405.0> terminating
** (Postgrex.Error) ERROR 42703 (undefined_column) column "id" does not exist
query: INSERT INTO "appointments_services" ("appointment_id","service_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id"
(ecto_sql 3.11.1) lib/ecto/adapters/sql.ex:1054: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto 3.11.1) lib/ecto/repo/schema.ex:775: Ecto.Repo.Schema.apply/4
(ecto 3.11.1) lib/ecto/repo/schema.ex:377: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ecto 3.11.1) lib/ecto/association.ex:1584: Ecto.Association.ManyToMany.on_repo_change/5
(ecto 3.11.1) lib/ecto/association.ex:648: anonymous fn/8 in Ecto.Association.on_repo_change/7
(elixir 1.15.4) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.11.1) lib/ecto/association.ex:644: Ecto.Association.on_repo_change/7
(elixir 1.15.4) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.11.1) lib/ecto/association.ex:589: Ecto.Association.on_repo_change/4
(ecto 3.11.1) lib/ecto/repo/schema.ex:955: Ecto.Repo.Schema.process_children/5
(ecto 3.11.1) lib/ecto/repo/schema.ex:1033: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto_sql 3.11.1) lib/ecto/adapters/sql.ex:1358: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.6.0) lib/db_connection.ex:1710: DBConnection.run_transaction/4
(medussa_studio 0.1.0) lib/medussa_studio_web/live/appointment_live/form_component.ex:117: MedussaStudioWeb.AppointmentLive.FormComponent.save_appointment/3
(phoenix_live_view 0.20.7) lib/phoenix_live_view/channel.ex:729: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
(telemetry 1.2.1) /Users/amir/Desktop/medussa_studio/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
(phoenix_live_view 0.20.7) lib/phoenix_live_view/diff.ex:209: Phoenix.LiveView.Diff.write_component/4
(phoenix_live_view 0.20.7) lib/phoenix_live_view/channel.ex:661: Phoenix.LiveView.Channel.component_handle/4
(stdlib 5.0.2) gen_server.erl:1077: :gen_server.try_handle_info/3
(stdlib 5.0.2) gen_server.erl:1165: :gen_server.handle_msg/6
Any help appreciated.
Thanks!