принадлежат нескольким родителям

Привет, я новичок в Elixir и моделях/БД/API в целом, и я немного не понимаю, как добиться следующего:

Я хочу создать событие, когда я выполняю POST в своем API для /v1/events отправки как tag_id, так и gate_id, но я не знаю, как это обработать в моем контроллере.

Я сделал это с более простыми моделями, где они просто belong_to один родитель, и я просто передаю build_assoc в changeset, однако я не понимаю, как это сделать с несколькими родителями. Я даже попробовал схематичное решение, чтобы вручную создать набор изменений, вручную установив gate_id и tag_id, как это Event.changeset(%Event{"gate_id" => gate_id, "tag_id" => tag_id}, event_params), однако он выдал ошибку, сказав, что gate_id и tag_id не являются частью модели.

Итак, два вопроса: как правильно поступить в этой ситуации? Я даже близко или мои модели неверны?

Также хорошо ли звучит POST для /v1/events, передавая оба идентификатора, или я тоже потерялся в этом?

Модели для справки

Тег модели:

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

person user1364649    schedule 20.04.2016    source источник
comment
Попробуйте изменить %Event{"gate_id" => gate_id, "tag_id" => tag_id} на %Event{gate_id: gate_id, tag_id: tag_id}, чтобы исправить последнюю ошибку.   -  person Dogbert    schedule 21.04.2016


Ответы (1)


Можете ли вы также опубликовать свою ошибку и миграцию для 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
person vikram7    schedule 20.04.2016
comment
Добавил required_fields и обновил мой вопрос с предложенными вами файлами и текущей ошибкой. - person user1364649; 21.04.2016
comment
Спасибо, ребята, комбинация этого, чтобы гарантировать, что tag_id и gate_id всегда были там, и комментарий @Dogbert, чтобы исправить мою текущую проблему с синтаксисом, решил мои проблемы. - person user1364649; 21.04.2016
comment
@ user1364649 обратите внимание, что добавление tag_id и gate_id к @required_fields позволит пользователям самостоятельно устанавливать для этих полей произвольное значение. Я не знаю, хотите ли вы запретить это или не видеть, поскольку по умолчанию вы получаете их из conn.assigns. - person Dogbert; 21.04.2016
comment
@Dogbert Интересно, я немного запутался. Итак, перед добавлением этого у меня было @required_fields ~(), что означает, что все поля обязательны по умолчанию, так почему я должен был их добавить? Это потому, что они на самом деле не являются полями в моей модели? Вы правы, я позволяю пользователю передавать tag_id и gate_id и полагаться на ограничения БД. Это нормальный подход? - person user1364649; 21.04.2016