2016-01-16 22 views
7

Diciamo che ho questi schemi:Ecto associazione a più di uno schemi

defmodule Sample.Post do 
    use Ecto.Schema 

    schema "post" do 
    field :title 
    has_many :comments, Sample.Comment 
    end 
end 

defmodule Sample.User do 
    use Ecto.Schema 

    schema "user" do 
    field :name 
    has_many :comments, Sample.Comment 
    end 
end 

defmodule Sample.Comment do 
    use Ecto.Schema 

    schema "comment" do 
    field :text 
    belongs_to :post, Sample.Post 
    belongs_to :user, Sample.User 
    end 
end 

Le mie domande è come posso usare Ecto.build_assoc per salvare un commento?

iex> post = Repo.get(Post, 13) 
%Post{id: 13, title: "Foo"} 
iex> comment = Ecto.build_assoc(post, :comments) 
%Comment{id: nil, post_id: 13, user_id: nil} 

Finora è ok, tutto ciò che devo fare è usare la stessa funzione per impostare il user_id nel mio Comment struct, tuttavia, poiché il valore di ritorno di build_assoc è Comment struct, non posso utilizzare la stessa funzione

iex> user = Repo.get(User, 1) 
%User{id: 1, name: "Bar"} 
iex> Ecto.build_assoc(user, :comment, comment) 
** (UndefinedFunctionError) undefined function: Sample.Comment.delete/2 
... 

ho due opzioni, ma nessuno di loro sembra buono per me:

primo uno è quello di impostare manualmente user_id!

iex> comment = %{comment| user_id: user.id} 
%Comment{id: nil, post_id: 13, user_id: 1} 

secondo è quello di convertire la struttura per la mappa e ... non ho nemmeno voglia di andare lì

Qualsiasi suggerimento?

risposta

8

Perché non vuoi convertire la struttura in mappa? È veramente facile

build_assoc prevede la mappa degli attributi come ultimo valore. Internamente tenta di cancellare il tasto :__meta__. Le strutture hanno compilazione garanzie di tempo, che conterrà tutti i campi definiti, in modo da stanno ottenendo:

** (UndefinedFunctionError) undefined function: Sample.Comment.delete/2 

ma si può solo scrivere:

comment = Ecto.build_assoc(user, :comment, Map.from_struct comment) 

e tutto funzionerà bene.

+0

Ho pensato di rimuovere '__meta__' prima di inviarlo a' build_assoc '! – slashmili

3

Basta passarlo insieme con build_assoc

iex> comment = Ecto.build_assoc(post, :comments, user_id: 1) 
%Comment{id: nil, post_id: 13, user_id: 1} 

Controllare here per maggiori dettagli.

+3

Non volevo avere un codice esplicito usando xxx_id – slashmili