belong_to 多个 parents
belong_to multiple parents
嗨,我是 Elixir 的新手,一般来说 models/DB/APIs,我对如何实现以下目标有点迷茫:
我想创建一个事件,当我在 API 中执行 POST 到 /v1/events
同时发送 tag_id
和 gate_id
但我没有我不知道如何在我的控制器中处理这个问题。
我用更简单的模型做到了这一点,它们只有 belong_to
一个 parent 而我只是将 build_assoc
输送到 changeset
,但是,我迷失了如何使用多个 parent 来做到这一点。我什至尝试了一个粗略的解决方案来手动创建一个变更集,手动设置 gate_id
和 tag_id
像这样 Event.changeset(%Event{"gate_id" => gate_id, "tag_id" => tag_id}, event_params)
但是它错误地说 gate_id
和 tag_id
不是模型的一部分。
所以两个问题:
处理这种情况的正确方法是什么?我什至很接近还是我的模型有误?
POST 到 /v1/events
同时传递两个 ID 听起来不错,还是我也迷失在其中?
型号供参考
标签模型:
defmodule Tracker.Tag do
use Tracker.Web, :model
schema "tags" do
field :epc, :string
field :name, :string
field :is_active, :boolean, default: false
field :is_inside, :boolean, default: false
has_many :events, Tracker.Event
timestamps
end
@required_fields ~w(epc name is_active is_inside)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:events, required: false)
end
end
门型号:
defmodule Tracker.Gate do
use Tracker.Web, :model
schema "gates" do
field :name, :string
field :direction_in, :boolean, default: false
field :antenna, :integer
belongs_to :reader, Tracker.Reader
has_many :events, Tracker.Event
timestamps
end
@required_fields ~w(name direction_in antenna)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:events, required: false)
end
end
更新:更多信息
事件模型:
defmodule Tracker.Event do
use Tracker.Web, :model
schema "events" do
belongs_to :tag, Tracker.Tag
belongs_to :gate, Tracker.Gate
timestamps
end
@required_fields ~w()
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
事件迁移:
defmodule Tracker.Repo.Migrations.CreateV1.Event do
use Ecto.Migration
def change do
create table(:events) do
add :tag_id, references(:tags, on_delete: :nothing)
add :gate_id, references(:gates, on_delete: :nothing)
timestamps
end
create index(:events, [:tag_id])
create index(:events, [:gate_id])
end
end
事件控制器创建函数(有点迷失在这个函数上)
def create(conn, %{"event" => event_params}) do
gate_id = conn.assigns.gate_id
tag_id = conn.assigns.tag_id
changeset = Event.changeset(%Event{"gate_id" => gate_id, "tag_id" => tag_id}, event_params)
case Repo.insert(changeset) do
{:ok, event} ->
conn
|> put_status(:created)
|> put_resp_header("location", v1_event_path(conn, :show, event))
|> render("show.json", event: event)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Tracker.ChangesetView, "error.json", changeset: changeset)
end
end
我得到的最新错误是
== Compilation error on file web/controllers/v1/event_controller.ex ==
** (CompileError) web/controllers/v1/event_controller.ex:22: unknown key "gate_id" for struct Tracker.Event
您能否 post 您的错误以及 Event
的迁移?我相信您需要将 tag_id
和 gate_id
添加到模型中的必填字段:
defmodule Tracker.Event do
use Tracker.Web, :model
schema "events" do
belongs_to :tag, Tracker.Tag
belongs_to :gate, Tracker.Gate
timestamps
end
@required_fields ~w(tag_id gate_id)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
嗨,我是 Elixir 的新手,一般来说 models/DB/APIs,我对如何实现以下目标有点迷茫:
我想创建一个事件,当我在 API 中执行 POST 到 /v1/events
同时发送 tag_id
和 gate_id
但我没有我不知道如何在我的控制器中处理这个问题。
我用更简单的模型做到了这一点,它们只有 belong_to
一个 parent 而我只是将 build_assoc
输送到 changeset
,但是,我迷失了如何使用多个 parent 来做到这一点。我什至尝试了一个粗略的解决方案来手动创建一个变更集,手动设置 gate_id
和 tag_id
像这样 Event.changeset(%Event{"gate_id" => gate_id, "tag_id" => tag_id}, event_params)
但是它错误地说 gate_id
和 tag_id
不是模型的一部分。
所以两个问题: 处理这种情况的正确方法是什么?我什至很接近还是我的模型有误?
POST 到 /v1/events
同时传递两个 ID 听起来不错,还是我也迷失在其中?
型号供参考
标签模型:
defmodule Tracker.Tag do
use Tracker.Web, :model
schema "tags" do
field :epc, :string
field :name, :string
field :is_active, :boolean, default: false
field :is_inside, :boolean, default: false
has_many :events, Tracker.Event
timestamps
end
@required_fields ~w(epc name is_active is_inside)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:events, required: false)
end
end
门型号:
defmodule Tracker.Gate do
use Tracker.Web, :model
schema "gates" do
field :name, :string
field :direction_in, :boolean, default: false
field :antenna, :integer
belongs_to :reader, Tracker.Reader
has_many :events, Tracker.Event
timestamps
end
@required_fields ~w(name direction_in antenna)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:events, required: false)
end
end
更新:更多信息
事件模型:
defmodule Tracker.Event do
use Tracker.Web, :model
schema "events" do
belongs_to :tag, Tracker.Tag
belongs_to :gate, Tracker.Gate
timestamps
end
@required_fields ~w()
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
事件迁移:
defmodule Tracker.Repo.Migrations.CreateV1.Event do
use Ecto.Migration
def change do
create table(:events) do
add :tag_id, references(:tags, on_delete: :nothing)
add :gate_id, references(:gates, on_delete: :nothing)
timestamps
end
create index(:events, [:tag_id])
create index(:events, [:gate_id])
end
end
事件控制器创建函数(有点迷失在这个函数上)
def create(conn, %{"event" => event_params}) do
gate_id = conn.assigns.gate_id
tag_id = conn.assigns.tag_id
changeset = Event.changeset(%Event{"gate_id" => gate_id, "tag_id" => tag_id}, event_params)
case Repo.insert(changeset) do
{:ok, event} ->
conn
|> put_status(:created)
|> put_resp_header("location", v1_event_path(conn, :show, event))
|> render("show.json", event: event)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Tracker.ChangesetView, "error.json", changeset: changeset)
end
end
我得到的最新错误是
== Compilation error on file web/controllers/v1/event_controller.ex ==
** (CompileError) web/controllers/v1/event_controller.ex:22: unknown key "gate_id" for struct Tracker.Event
您能否 post 您的错误以及 Event
的迁移?我相信您需要将 tag_id
和 gate_id
添加到模型中的必填字段:
defmodule Tracker.Event do
use Tracker.Web, :model
schema "events" do
belongs_to :tag, Tracker.Tag
belongs_to :gate, Tracker.Gate
timestamps
end
@required_fields ~w(tag_id gate_id)
@optional_fields ~w()
def changeset(model, params \ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end