Elixir 关联的变更集函数

Elixir 关联的变更集函数,elixir,ecto,Elixir,Ecto,我有以下模式: schema "countries" do belongs_to :code, CountryCode, references: :alpha2 belongs_to :language, LanguageCode, references: :code field :text, :string timestamps end 我的问题是,如何为上述模式编写变更集函数 我试过: def changeset(model, params \\ %

我有以下模式:

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>
我有:

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

我在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>
iex(4)>v=%%{code:%%{code:CH},语言:%%{alpha2:DE},文本:“Schweiz}
%{code:%%{code:“CH”},语言:%%{alpha2:“DE”},文本:“Schweiz”}
iex(5)>c=Country.changeset(%Country{},v)

#外部变更集

正在生成的变更集正在尝试插入3条新记录:国家、语言代码和国家代码

参数中的数据不足,无法插入所有这些记录:

%{code: %{code: "CH"}, language: %{alpha2: "DE"}, text: "Schweiz"}
如果没有
alpha2
alpha3
字段,则无法插入CountryCode表:

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>
如果不想插入所有这些表,则需要填充
language\u id
code\u id
参数

params = %{language_id: "DE", code_id: "CH", text: "Schweiz"}
然后从变更集函数中删除
cast\u assoc
调用:

def changeset(model, params \\ %{}) do
  model
  |> cast(params, [:code_id, :language_id, :text])
  |> validate_required([:code_id, :language_id, :text])
end
或者,您可以预加载关联并使用
put\u 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
for
cast\u assoc
cast\u assoc
put\u 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
换句话说,当关联数据与父结构同时管理时,cast_assoc/3非常有用。如果关联的每一方都是单独管理的,则最好使用put_assoc/3并直接指示EXTO关联的外观


因为您没有发布其余的模式,所以很难说。您的“语言”数据可能无效。它适用于简单的情况:我在post上插入语言代码模式。我再次更新了我的post。
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