2015-08-17 20 views

risposta

15

C'è un semplice esempio di gestione della situazione 1-1.

Immaginiamo di avere una e una Engine modelli Car e ovviamente un Car has_one Engine. Quindi c'è il codice per il modello di auto

defmodule MyApp.Car do 
    use MyApp.Web, :model 

    schema "cars" do 
    field :name, :string    

    has_one :engine, MyApp.Engine 

    timestamps 
    end 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, ~w(name), ~w()) 
    |> validate_length(:name, min: 5, message: "No way it's that short")  
    end 

end 

e il modello del motore

defmodule MyApp.Engine do 
    use MyApp.Web, :model 

    schema "engines" do 
    field :type, :string    

    belongs_to :car, MyApp.Car 

    timestamps 
    end 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, ~w(type), ~w()) 
    |> validate_length(:type, max: 10, message: "No way it's that long")  
    end 

end 

semplice modello per la forma ->

<%= form_for @changeset, cars_path(@conn, :create), fn c -> %> 

    <%= text_input c, :name %> 

    <%= inputs_for c, :engine, fn e -> %> 

    <%= text_input e, :type %> 

    <% end %> 

    <button name="button" type="submit">Create</button> 

<% end %> 

ed il regolatore ->

defmodule MyApp.CarController do 
    use MyApp.Web, :controller 
    alias MyApp.Car 
    alias MyApp.Engine 

    plug :scrub_params, "car" when action in [:create] 

    def new(conn, _params) do  
    changeset = Car.changeset(%Car{engine: %Engine{}})  
    render conn, "new.html", changeset: changeset 
    end 

    def create(conn, %{"car" => car_params}) do  
    engine_changeset = Engine.changeset(%Engine{}, car_params["engine"]) 
    car_changeset = Car.changeset(%Car{engine: engine_changeset}, car_params) 
    if car_changeset.valid? do 
     Repo.transaction fn -> 
     car = Repo.insert!(car_changeset) 
     engine = Ecto.Model.build(car, :engine) 
     Repo.insert!(engine) 
     end 
     redirect conn, to: main_page_path(conn, :index) 
    else 
     render conn, "new.html", changeset: car_changeset 
    end 
    end  

end 

e un interessante post sul blog l'argomento che può chiarire anche alcune cose ->here

+0

L'esempio può avere alcuni piccoli errori da quando non ho avuto la possibilità di testare proprietà o essere scritto in modo non è un esattamente corretto visto che sono nuovo di questo quadro me stesso ma io spero che possa aiutare qualcuno a risparmiare un po 'di tempo a capire quelle cose da solo. Sto solo cercando di trovare le risposte ad alcune domande più semplici visto che non ci sono molte informazioni sull'argomento – JustMichael

+0

Il problema con questa soluzione se, ad esempio, se Car 'avesse un vincolo come l'unicità per il suo nome, allora la transazione fallirebbe e nessun errore sarebbe dato per il modulo. Sono bloccato in questo: http://stackoverflow.com/a/38035026?noredirect=1 – masylum

+0

Ecco un test che mostra come si farebbe l'inserto annidato in ecto 2, https://github.com/elixir-ecto/ ecto/blob/6f1971f4120b84e1a441792feb77ba451c4fc783/integration_test/cases/repo.exs # L720 – opsb

2

Si è verificato lo stesso problema con una relazione has_many. Purtroppo, un Car non può avere molti Engines, quindi mi piacerebbe prendere lo stesso esempio in questo blogpost, di un TodoList, con molte TodoItems

TodoList modello:

defmodule MyApp.TodoList do 
    use MyApp.Web, :model 

    schema "todo_lists" do 
    field :title, :string    

    has_many :todo_items, MyApp.TodoItem 

    timestamps 
    end 

    def changeset(model, params \\ :{}) do 
    model 
    |> cast(params, [:title]) 
    |> cast_assoc(:todo_items) 
    end 
end 

TodoItem modello:

defmodule MyApp.TodoItem do 
    use MyApp.Web, :model 

    schema "todo_items" do 
    field :body, :string 

    belongs_to :todo_list, MyApp.TodoList 

    timestamps 
    end 

    def changeset(model, params \\ :{}) do 
    model 
    |> cast(params, [:body]) 
    end 
end 

Ecco la creazione del modulo TodoList. Per semplificare le cose, aggiungiamo un elemento per ora.

<%= form_for @changeset, todo_lists_path(@conn, :create), fn f -> %>  
    <%= text_input f, :title %> 
    <%= inputs_for f, :todo_items, fn i -> %> 
    <%= text_input i, :body %> 
    <% end %> 
    <button name="button" type="submit">Create</button> 
<% end %> 

Questo è il modo in TodoListController sarebbe simile. Il metodo create era il più difficile da ottenere. Ho dovuto scavare nei test Ecto per trovare un modo per farlo funzionare. Link

defmodule MyApp.TodoListController do 
    use MyApp.Web, :controller 

    alias MyApp.TodoList 
    alias MyApp.TodoItem 

    def new(conn, _params) do 
    todo_item = TodoItem.changeset(%TodoItem{}) 
    changeset = TodoList.changeset(%TodoList{todo_items: [todo_item]}) 

    render conn, "new.html", changeset: changeset 
    end 

    def create(conn, %{"todo_list" => todo_list_params}) do 
    todo_item_changeset = 
     TodoItem.changeset(%TodoItem{}, todo_item["todo_items"]["0"]) 
    changeset = 
     TodoList.changeset(%TodoList{}, %{title: todo_list_params["title"]}) 
     |> Ecto.Changeset.put_assoc(:todo_items, [todo_item_changeset]) 

    case Repo.insert(changeset) do 
     {:ok, company} -> 
     conn 
     |> put_flash(:info, "TodoList created!") 
     |> redirect(to: page_path(conn, :index)) 
     {:error, changeset} -> 
     conn 
     |> render "new.html", changeset: changeset 
    end 
    end 
end 

http://pranavsingh.co/storing-nested-associations-with-phoenix-forms/

+2

Qualche idea su come aggiungere più oggetti, aggiungendoli/rimuovendoli in modo dinamico nella forma? –

Problemi correlati