8

Phoenix 框架是否使用任何类型的回调过滤器,例如Rails中的那些?我知道可以验证变更集,但我正在寻找实现诸如before_createbefore_saveafter_commit.

4

2 回答 2

13

Ecto 确实:https ://hexdocs.pm/ecto/#!Ecto.Model.Callbacks.html

它们与 Rails 的明显不同:它们接收并必须返回变更集,并且必须用于数据一致性(不要使用它们来发送电子邮件等)。

于 2015-04-27T20:54:19.717 回答
13

从 Ecto 2.0 开始,回调已被完全删除。

那么现在如何处理回调呢?这里有两种方法

对于before_回调,您可以使用Changeset本身。回调被移除的原因之一是因为许多开发人员在许多变更集就足够的情况下依赖回调。因此,只需将所需的功能应用于您的变更集,

def changeset(post, params \\ :empty) do
  post
  |> cast(params, @required_params, @optional_params)
  |> validate_length(:title, min: 3)
  |> validate_length(:metadata, min: 3)
  |> implement_a_before_callback
end

def implement_a_before_callback(changeset)
   #Apply required actions and return Changeset
end

另一种方法是使用Ecto.Multi将多个 repo 操作组合在一起。从文档

Ecto.Multi 使得打包应该一起执行的操作(在单个数据库事务中)成为可能,并提供了一种在不实际执行它们的情况下内省排队操作的方法。每个操作都有一个唯一的名称,将标识其结果或在发生故障时帮助识别故障位置。因此,当您希望一次发生一组与数据相关的操作时,您可以使用Multibefore_after_回调都可以在这里替换。

一个例子是

  # In defmodule Service
  def password_reset(account, params) do
    Multi.new
    |> Multi.update(:account, Account.password_reset_changeset(account, params))
    |> Multi.insert(:log, Log.password_reset_changeset(account, params))
    |> Multi.delete_all(:sessions, assoc(account, :sessions))
  end

运行它使用

result = Repo.transaction(Service.password_reset(account, params))

您必须记住,您必须执行与数据相关的查询,而不是执行其他任务,例如发送电子邮件。为此,您可以简单地对结果进行模式匹配并执行适当的操作。如果交易成功,让您想发送邮件,如果不成功,则显示一些错误消息

case result do
  {:ok, %{account: account, log: log, sessions: sessions}} ->
    # Operation was successful, perform actions like sending a mail
  {:error, failed_operation, failed_value, changes_so_far} ->
    # One of the operations failed. Raise error message
end

资源:

于 2016-06-26T14:44:20.260 回答