39

我在理解changesetin 模型时遇到问题。它能做什么?我们可以在一个模型中拥有多个变更集吗?例如,一个用于创建,另一个用于更新。

有人可以用简单的方式详细说明,以便帮助其他人来凤凰城。

4

2 回答 2

27

文档中:

变更集允许在操作模型时过滤、转换、验证和定义约束。

Ecto 模块的介绍性文档中有一个使用变更集的示例。函数 change/2 和 cast/4 是创建变更集的常用入口点,而其余函数对于操作它们很有用。

变更集用于创建和修改模型。变更集实际上是一个存储一组变更(以及验证规则)的结构。您将变更集传递给您的 Ecto Repo 以保留有效的变更。

Ecto 的当前主分支在更新时将模型传递给 Repo 时删除了隐式转换,这意味着使用变更集是更新模型的唯一方法。

从变更日志:

鉴于 Repo.update/2 的模型已被弃用,因为它无效且容易出错,因为无法跟踪更改

就每个模型有多个变更集而言,答案肯定是肯定的。变更集只是一个函数。实际上,您甚至不需要将变更集函数放入模型中,但这是放置它们的常见位置。

如果您在注册用户时需要比更新用户更多的字段,那么您可以使用不同的必填字段定义 aregister_changeset和 a 。create_changeset

于 2015-10-17T11:57:31.240 回答
17

如果您对 Rails 有点熟悉,ActiveRecord 在您的模型中集中了数据库访问、查询生成和验证,Ecto 将这些职责划分为单独的模块。

ActiveRecord 方法在模型类或实例中执行,而 Ecto 期望您将模型、查询或变更集传递给它的函数。

Ecto 使用变更集来执行验证,而不是处理模型内部的验证。

Ecto 变更集提供验证和约束,万一出现问题,最终会变成错误。

它们之间的区别在于无需与数据库交互就可以执行验证,因此始终在尝试插入或更新数据库中的条目之前执行。

但是,只有在数据库中执行操作时才能以安全的方式检查约束。因此,总是在约束之前检查验证。如果验证失败,甚至不会检查约束。

让我们看一个例子:

defmodule User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name
    field :email
    field :age, :integer
  end

  def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> validate_inclusion(:age, 18..100)
    |> unique_constraint(:email)
  end
end

在上面的changeset/2函数中,我们定义了两个验证 - 一个用于检查电子邮件格式,另一个用于检查年龄 - 以及电子邮件字段中的唯一约束。

假设给出了电子邮件,但年龄无效。变更集将有以下错误:

changeset = User.changeset(%User{}, %{age: 0, email: "mary@example.com"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [age: "is invalid"]

在这种情况下,我们没有检查电子邮件字段中的唯一约束,因为数据没有验证。但是,让我们修正年龄并假设电子邮件已经存在于数据库中:

changeset = User.changeset(%User{}, %{age: 42, email: "mary@example.com"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [email: "has already been taken"]

当检查发生时,验证和约束定义了一个明确的边界。通过将约束移至数据库,我们还提供了一种安全、正确且无数据竞争的方法来检查用户输入。

你,可以在这里找到更多细节Ecto Change Set

于 2016-05-01T08:25:35.087 回答