gpt4 book ai didi

elixir - 用于关联的变更集函数

转载 作者:行者123 更新时间:2023-12-02 03:01:38 25 4
gpt4 key购买 nike

我有以下架构:

schema "countries" do

belongs_to :code, CountryCode, references: :alpha2
belongs_to :language, LanguageCode, references: :code
field :text, :string

timestamps
end

我的问题是,如何为上面的模式编写变更集函数?

我尝试过:

  def changeset(model, params \\ %{}) do

model
|> cast(params, [:text])
|> cast_assoc(:code)
|> cast_assoc(:language)
|> validate_required([:code, :language, :text])

end

我收到错误消息:

#Ecto.Changeset<action: nil, changes: %{text: "Switzerland"},
errors: [language: {"is invalid", [type: :map]},
code: {"is invalid", [type: :map]}], data: #Busiket.Country<>, valid?: false>

更新

我重写了变更集函数:

def changeset(model, params \\ %{}) do

model
|> cast(params, [:code_id, :language_id, :text])
|> cast_assoc(:code)
|> cast_assoc(:language)
|> validate_required([:code, :language, :text])
end

我有:

#Ecto.Changeset<action: nil, changes: %{text: "Switzerland"},
errors: [language: {"is invalid", [type: :map]},
code: {"is invalid", [type: :map]}], data: #Busiket.Country<>, valid?: false>

抱歉,这是我的 LanguageCode 的架构:

schema "languages_code" do

has_one :code, Country, foreign_key: :lang
field :text, :string

timestamps
end

更新

我在shell中再次测试:

iex(4)> v = %{code: %{code: "CH"}, language: %{alpha2: "DE"}, text: "Schweiz"}
%{code: %{code: "CH"}, language: %{alpha2: "DE"}, text: "Schweiz"}
iex(5)> c = Country.changeset(%Country{}, v)
#Ecto.Changeset<action: nil,
changes: %{code: #Ecto.Changeset<action: :insert, changes: %{},
errors: [alpha2: {"can't be blank", []}, alpha3: {"can't be blank", []}],
data: #Busiket.CountryCode<>, valid?: false>,
language: #Ecto.Changeset<action: :insert, changes: %{},
errors: [code: {"can't be blank", []}, text: {"can't be blank", []}],
data: #Busiket.LanguageCode<>, valid?: false>, text: "Schweiz"}, errors: [],
data: #Busiket.Country<>, valid?: false>

我忘了提及,language_code 表上的数据已经可用:

enter image description here

最佳答案

正在生成的变更集正在尝试插入 3 个新记录:Country、LanguageCode 和 CountryCode。

您的参数中没有足够的数据来插入所有这些记录:

%{code: %{code: "CH"}, language: %{alpha2: "DE"}, text: "Schweiz"}

如果没有 alpha2alpha3 字段,它无法插入到 CountryCode 表中:

code: #Ecto.Changeset<action: :insert, 
changes: %{},
errors: [alpha2: {"can't be blank", []}, alpha3: {"can't be blank", []}],
data: #Busiket.CountryCode<>,
valid?: false>`

如果没有 codetext 字段,它就无法插入到 LanguageCode 表中:

language: #Ecto.Changeset<action: :insert, 
changes: %{},
errors: [code: {"can't be blank", []}, text: {"can't be blank", []}],
data: #Busiket.LanguageCode<>,
valid?: false>

如果您不打算插入到所有这些表中,则需要填充 language_idcode_id 参数。

params = %{language_id: "DE", code_id: "CH", text: "Schweiz"}

然后从变更集函数中删除 cast_assoc 调用:

def changeset(model, params \\ %{}) do
model
|> cast(params, [:code_id, :language_id, :text])
|> validate_required([:code_id, :language_id, :text])
end

或者,您可以预加载关联并使用 put_assoc:

def changeset(
model = %Country{},
country_code = %CountryCode{},
language_code = %LanguageCode{},
params \\ %{}) do

model
|> cast(params, [:text])
|> put_assoc(:code, country_code)
|> put_assoc(:language, language_code)
|> validate_required([:text, :code, :language])
end

docs for cast_assoccast_assocput_assoc 之间的差异有一些额外的解释:

In other words, cast_assoc/3 is useful when the associated data is managed alongside the parent struct, all at once. If each side of the association is managed separately, it is preferable to use put_assoc/3 and directly instruct Ecto how the association should look like.

关于elixir - 用于关联的变更集函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40697564/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com