2015-07-16 8 views
12

Ho i seguenti modelli:Inserire un modello con l'associazione has_many

# Foo model 
schema "foo" do 
    field :name, :string 
    has_many: :bars, App.Bar 
end 

# App model 
schema "bar" do 
    field :name, :string 
    belongs_to: foo, App.Foo 
end 

e questa forma:

# form.html (Foo) 
<%= form_for @changeset, @action, fn f -> %> 
    <%= text_input f, :name, class: "form-control" %> 
    <%= submit "Submit", class: "btn btn-primary" %> 
<% end %> 

All'interno di questo modulo, come posso aggiungere campi di testo per popolare il mio nuovo Foo con Bars ?

Quanto segue non funziona perché bars non è precaricato:

<%= text_input f, :bars, class: "form-control" %> 

Sono sulla strada giusta? In tal caso, come posso pre-caricare Bars nel modulo?

Update, regolatore:

def new(conn, _params) do 
    changeset = %Foo{} |> Repo.preload(:bars) |> Foo.changeset 
    render(conn, "new.html", changeset: changeset) 
end 

def create(conn, %{"foo" => foo_params}) do 
    changeset = %Foo{} |> Repo.preload(:bars) |> Foo.changeset(foo_params) 

    if changeset.valid? do 
    Repo.insert!(changeset) 

    conn 
    |> put_flash(:info, "Foo created successfully.") 
    |> redirect(to: foo_path(conn, :index)) 
    else 
    render(conn, "new.html", changeset: changeset) 
    end 
end 

Il precarico sembra funzionare, ma ottengo un Argument error al raggiungimento <%= text_input f, :bars, class: "form-control" %>:

[error] #PID<0.280.0> running App.Endpoint terminated 
Server: 192.168.48.202:4000 (http) 
Request: GET/
** (exit) an exception was raised: 
    ** (ArgumentError) argument error 
     :erlang.bit_size([]) 
     (phoenix_html) lib/phoenix_html/tag.ex:66: anonymous fn/2 in Phoenix.HTML.Tag.tag_attrs/1 
     (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3 
     (phoenix_html) lib/phoenix_html/tag.ex:35: Phoenix.HTML.Tag.tag/2 
     (app) web/templates/foo/form.html.eex:16: anonymous fn/1 in App.FooView.form.html/1 
     (phoenix_html) lib/phoenix_html/form.ex:181: Phoenix.HTML.Form.form_for/4 
     (app) web/templates/foo/form.html.eex:1: App.FooView."form.html"/1 
     (app) web/templates/foo/new.html.eex:3: App.FooView."new.html"/1 
+0

Che aspetto ha il controller? Potresti precaricare Bar nei dati Foo con qualcosa come '' 'foo = Foo |> Repo.get (id) |> Repo.preload ([: barre])' '' assumendo che tu stia usando Ecto e questo è per mostrare una singola barra. Quindi usa un ciclo for nel modello per accedere a ogni foo.bar –

+0

L'azione è # new/# create, non #show. Aggiornato la domanda con il preloading del 'Bars'. – Kernael

+0

@Kernael, potresti pubblicare l'errore completo nella tua domanda? –

risposta

12

Partenza post di Jose il Working with Associations and Embeds per un esempio di robusta utilizzando ToDoLists e ToDoItems (in particolare la sezione intitolata "associazioni nidificati e incorpora"). L'esempio seguente è un esempio derivativo che riflette la combinazione di Foos con Bars.

Per cominciare, siete sulla strada giusta con:
has_many: :bars, App.Bar

Modificare il modulo in modo da riflettere:

# form.html (Foo) 
<%= form_for @changeset, @action, fn f -> %> 
    <%= text_input f, :name, class: "form-control" %> 
    <%= inputs_for f, :bars, fn i -> %> 
    <div class="form-group"> 
     <%= label i, :name, "Bar ##{i.index + 1}", class: "control-label" %> 
     <%= text_input i, :name, class: "form-control" %> 
    </div> 
<% end %> 
    <%= submit "Submit", class: "btn btn-primary" %> 
<% end %> 

Questo utilizza la funzione inputs_for/4 da Phoenix.HTML.Form per generare i campi per la vostra: associazione di bar. Qui abbiamo etichettato ogni sequenza, "Bar # 1" e "Bar # 2", nonché i tag text_input forniti per ciascuno.

Ora, che è necessario regolare new e create azioni del controller in modo da riflettere l'inclusione di alcuni bar (diciamo due, per esempio):

def new(conn, _params) do 
    changeset = %Foo{} |> Foo.changeset(%Foo{bars: [%MyApp.Bar{}, %MyApp.Bar{}]}) 
    render(conn, "new.html", changeset: changeset) 
end 

def create(conn, %{"foo" => foo_params}) do 
    changeset = %Foo{} |> Foo.changeset(foo_params) 

    case Repo.insert(changeset) do 

    conn 
    |> put_flash(:info, "Foo created successfully.") 
    |> redirect(to: foo_path(conn, :index)) 
    else 
    render(conn, "new.html", changeset: changeset) 
    end 
end 

vostri edit e update azioni avranno bisogno di precaricare le barre :

foo = Repo.get!(Foo, id) |> Repo.preload(:bars) 
2

Se il modello è annidato associazione è possibile utilizzare inputs_for per allegare dati nidificati al modulo. Ad esempio, vedere here nella sezione Input nidificati.

Problemi correlati