我希望我的所有模型都可以使用new
便捷功能,该功能返回自定义更改集。
类似的东西:
def new(attrs) do
changeset(%__MODULE__{}, attrs)
end
这样,当我需要变更集验证时,我可以致电:
Project.Model.new(%{param1: "param1"})
代替:
Project.Model.changeset(%Model{}, %{param1: "param1"})
我遇到的问题是当我实现以下宏时:
defmodule Project.Model do
defmacro __using__(_) do
quote do
use Ecto.Schema
import Ecto.Changeset
def new(attrs) do
changeset(%__MODULE__{}, attrs)
end
end
end
end
...这是行不通的,因为Ecto的schema "model" do ... end
需要在我的use Project.Model
语句之前进行编译,否则我将得到一个错误,该错误基本上表明我的模块未定义结构。
我可以仅将宏限制为new
函数,然后将其放在使用它的模块的中间,但这似乎令人困惑。
有什么想法吗?
根据要求,下面提供完整代码:
再一次,所有这一切的目的是使模型use Project.Model
获得便利函数new
,该函数接受属性并将其放入changeset
内,以便它们将在插入数据库之前进行验证。
正如一些人提到的那样,我得到的错误是,schema
必须先扩展,然后才能在宏中使用__MODULE__
,因为尚未定义该结构。
项目/user.ex
defmodule Project.User do
use Project.Model
schema "users" do
field :email, :string
field :first_name, :string
field :last_name, :string
timestamps()
end
def changeset(user, attrs) do
user
|> cast(attrs, [:email, :first_name, :last_name])
|> validate_required([:email, :first_name, :last_name])
end
end
project / model.ex
defmodule Project.Model do
defmacro __using__(_) do
quote do
use Ecto.Schema
import Ecto.Changeset
def new(attrs) do
changeset(%__MODULE__{}, attrs)
end
end
end
end
答案 0 :(得分:1)
要在定义结构之前使用结构,可以尝试以下技巧:
def new(attrs) do
changeset(struct(__MODULE__), attrs)
end
changeset
是您应该为每个模型定义的(可能具有不同的形状),所以我不确定以一般方式在new
中使用它是一个好主意。
答案 1 :(得分:1)
此代码的主要问题是AST扩展的宏顺序。我怀疑我理解为什么您手头有普通的旧商品Ecto.Changeset.change/2
时为什么会尝试使用注入的#changeset
。只要做:
defmodule Project.Model do
defmacro __using__(_) do
quote do
use Ecto.Schema
import Ecto.Changeset
def new(attrs) do
__MODULE__
|> struct(%{})
|> change(attrs)
end
end
end
end
您应该已经准备就绪,因为Ecto.Changeset.change/2
是正常功能,不会尝试扩展到AST。