2016-10-04 65 views
4

我是Elixir和Ecto的新手,我需要Ecto的has_many和cast_assoc帮助。无法理解基础知识,比如我如何用assoc关系创建新模型。如何使用Ecto的has_many和cast_assoc

这里是我的Has_Model:

​​3210

和这里的Belong_Model:

defmodule Example.Belong_Model do 
    use Ecto.Schema 
    import Ecto.Changeset 
    alias Example.Repo 
    alias Example.Belong_Model 

    schema "belong_models" do 
    belongs_to :has_model, Example.Has_Model 
    field :name, string 
    timestamps 
    end 

    def changeset(belong_model, params \\ %{}) do 
    belong_model 
    |> cast(params, [:name]) 
    |> cast_assoc(:has_model, required: true) 
    end 
end 

现在,我尝试做的是首先要创建一个Has_Model

iex()> changeset = Example.Has_Model.changeset(%Has_Model, %{name: "I have"}) 
iex()> Example.Repo.insert(changeset) 

这项工作好。

然后我想创建一个新的Belong_Model和使用以前创建Has_Model它:

iex()> has = Example.Has_Model |> Example.Repo.get_by(name: "I have") 
iex()> changeset = Example.Belong_Model.changeset(%Belong_Model, %{name: "I belong", belongs_to: has}) 

而这正是它失败:

** (Ecto.CastError) expected params to be a map, got: `%Example.Has_Model{__meta__: #Ecto.Schema.Metadata<:loaded, "has_models">, id: 1, inserted_at: #Ecto.DateTime<2016-10-04 19:39:38>, name: "I have", updated_at: #Ecto.DateTime<2016-10-04 19:39:38>, belong_models: #Ecto.Association.NotLoaded<association :belong_models is not loaded>}` 
    (ecto) lib/ecto/changeset.ex:345: Ecto.Changeset.do_cast/4 
    (example) lib/example/models/has_model.ex:15: Example.Has_Model.changeset/2 
    (ecto) lib/ecto/changeset/relation.ex:99: Ecto.Changeset.Relation.do_cast/5 
    (ecto) lib/ecto/changeset/relation.ex:235: Ecto.Changeset.Relation.single_change/5 
    (ecto) lib/ecto/changeset.ex:571: Ecto.Changeset.cast_relation/4 
    (example) lib/example/models/belong_model.ex:16: Example.Belong_Model.changeset/2 

发生了什么事和什么解决方案?我试着把这些参数全天调整,但我不明白。

+1

尝试更改'%{name:“我属于”,belongs_to:has}' - >'%{name:“我属于”,has_model_id:has.id}'。 – Dogbert

+0

这增加了正确的id,但是现在我不能在Belong_Model变更集上使用'cast_assoc(:has_model,required:true)',否则我得到错误:[has_model:{“can not be blank”,[] }]' – Gulliver

回答

1

我想你正在寻找的是build_assoc/3

iex()> has = Example.Has_Model |> Example.Repo.get_by(name: "I have") 
iex()> belong_assoc = Ecto.build_assoc(has, :belong_models, has_model_id: has.id, name: "I belong") 
iex()> Repo.insert!(belong_assoc) 

而且cast_assoc/3应该是这样使用:

iex()> changeset = Example.Belong_Model.changeset(%Belong_Model, %{name: "I belong", has_model: %{name: "I have"}) 
iex()> Repo.insert!(changeset) 

注:

对于给定关联的参数将从changeset.params中检索,关联模块中的changeset函数将会被检索被调用

+0

使用build_assoc示例,我确实可以将关联模型包括到新模型中,但它不使用变更集进行验证。如果在Repo.insert!(belongs_assoc)之前,我做了'changeset = Example.changeset(%Belong_Model {},belong_assoc)''我再次得到那个'(Ecto.CastError)期望的参数是一张地图,得到了......错误。 – Gulliver

+1

到目前为止,使用现有Has_Model创建新Belong_Model的唯一工作方式是使用has_model_id而不需要:true对cast_assoc如此:'iex()> changeset = Example.Belong_Model.changeset(%Belong_Model,%{名称:“我属于”,has_model_id:has.id})'。如果我在Belong_Model变更集上使用'cast_assoc(:has_model,required:true)',那么我得到一个错误,说它不能为空,即使我已经使用了has_model_id ... – Gulliver