使用Ecto插入之前查询记录(类似于AR回调)

问题描述 投票:1回答:1

我是Elixir和凤凰城的新手(不到10天),但对此感到非常兴奋,就像许多其他人一样,我来自Rails背景。

我知道Ecto不是AR,并且已经弃用或删除了回调但我需要添加一个自定义验证,该验证应该只在创建时发生并且需要执行查询。

这是我的Reservation模型基本上看起来像。

schema "reservations" do
  field :ends_at, :utc_datetime
  field :name, :string, null: false
  field :starts_at, :utc_datetime
  field :user_id, :id
end

然后我有另一个架构Slot,看起来像这样:

schema "slots" do
  field :ends_at, :utc_datetime
  field :name, :string, null: false
  field :starts_at, :utc_datetime
  field :admin_id, :id
end

每当我添加新的预订时,我都需要查询我的数据库以检查是否有任何匹配ends_atstarts_at的插槽。如果有,我需要阻止保存记录并向其添加错误(类似于我们使用throw :aborterrors.add完成的Rails中的错误)。

有人可以为此阐明一下吗?什么是Ecto这样做的方式?

最好的祝福

callback elixir phoenix-framework ecto
1个回答
1
投票

*编辑:使用单独的更改集添加示例以进行创建和更新

您可以在变更集验证链中添加自定义验证功能,并在其中执行数据库查询。

没有运行此代码,但这样的事情应该工作

# separate changeset for creation
def create_changeset(struct, params) do
  struct
  |> cast(params, [...list of fields...])
  |> validate_unique([:name]) # lets say it has to be unique
  |> validate_slots # -- custom validation
end

# separate changeset for updation, no slot-check
def update_changeset(struct, params) do
  struct
  |> cast(params, [...list of fields...])
  |> validate_unique([:name]) # lets say it has to be unique
end


def validate_slots(changeset) do
    starts_at = get_field(changeset, :starts_at)
    ends_at = get_field(changeset, :ends_at)
    slots = Repo.all(from s in Slot, where: s.starts_at == ^starts_at and s.ends_at == ^ends_at)

    if Enum.empty?(slots) do
      changeset
    else
      add_error( changeset, :starts_at, "has slot with similar starts_at/ends_at")
    end
end

#---- using the changesets
# creation
%Reservation{} |> Reservation.create_changeset(params) |> Repo.insert()

# updation
%Reservation{} |> Reservation.update_changeset(params) |> Repo.update()

虽然从它的外观来看,你应该将你的starts_at和ends_at标准化为一个名为booking_time_frame或其他东西的单独表,并为其添加唯一索引。

或者您可能最终会有更多类型的预订,然后必须检查3个表中的starts_at / ends_at,依此类推。

© www.soinside.com 2019 - 2024. All rights reserved.