【发布时间】:2017-08-21 15:13:54
【问题描述】:
抱歉,如果这听起来像是一个愚蠢的问题,但我被 Ecto 抛出的错误难住了。
我正在尝试实现一对一的多态关联。我已阅读有关在 Ecto 中实现多态关联的方法的文档,但我的要求需要一对一的关系。
guard -> guard_user -> user
operator -> operator_user -> user
在哪里
guard
-----
id
position
guard_user
----
guard_id
user_id
user
-----
id
email
password
name
operator 和 operator_user 表也是如此。
defmodule Example.Guards.Guard do
use Ecto.Schema
import Ecto.Changeset
alias Example.Guards.Guard
alias Example.Guards.GuardUser
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "guards" do
field :position, :string
has_one :guard_user, GuardUser
has_one :user, through: [:guard_user, :user]
timestamps()
end
@doc false
def changeset(%Guard{} = guard, attrs \\ %{}) do
guard
|> cast(attrs, [:position])
|> cast_assoc(:guard_user, required: true)
end
end
defmodule Example.Guards.GuardUser do
use Ecto.Schema
import Ecto.Changeset
alias Example.Guards.Guard
alias Example.Accounts.User
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "guard_user" do
belongs_to :guard, Guard
belongs_to :user, User
timestamps()
end
@doc false
def changeset(guard_user, attrs \\ %{}) do
guard_user
|> cast_assoc(:user, required: true)
end
end
defmodule Example.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Example.Accounts.User
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "users" do
field :email, :string
field :password, :string
timestamps()
end
@doc false
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:email, :password])
|> validate_required([:email, :password])
|> unique_constraint(:email)
end
end
当我运行测试时,
test "create guard" do
params = %{
"position" => "Guard",
"guard_user" => %{
"user" => %{
"email" => "example@gmail.com",
"password" => "example"
}
}
}
changeset = Guard.changeset(%Guard{}, params)
assert changeset.valid?
end
抛出以下错误:
** (FunctionClauseError) no function clause matching in Ecto.Changeset.cast_relation/4
The following arguments were given to Ecto.Changeset.cast_relation/4:
# 1
:assoc
# 2
%Example.Guards.GuardUser{__meta__: #Ecto.Schema.Metadata<:built, "guard_user">, guard: #Ecto.Association.NotLoaded<association :guard is not loaded>, guard_id: nil, id: nil, inserted_at: nil, updated_at: nil, user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: nil}
# 3
:user
# 4
[required: true]
Attempted function clauses (showing 2 out of 2):
defp cast_relation(type, %Ecto.Changeset{data: data, types: types}, _name, _opts) when data == nil or types == nil
defp cast_relation(type, %Ecto.Changeset{} = changeset, key, opts)
code: changeset = Guard.changeset(%Guard{}, params)
stacktrace:
(ecto) lib/ecto/changeset.ex:665: Ecto.Changeset.cast_relation/4
(ecto) lib/ecto/changeset.ex:712: anonymous fn/4 in Ecto.Changeset.on_cast_default/2
(ecto) lib/ecto/changeset/relation.ex:100: Ecto.Changeset.Relation.do_cast/5
(ecto) lib/ecto/changeset/relation.ex:237: Ecto.Changeset.Relation.single_change/5
(ecto) lib/ecto/changeset.ex:691: Ecto.Changeset.cast_relation/4
test/example/guards/guard_test.exs:29: (test)
【问题讨论】:
-
你能发布错误的整个堆栈跟踪吗?
-
@Dogbert 我已经编辑了帖子以包含堆栈跟踪
标签: elixir phoenix-framework ecto