get_by etimologia elixir phoenix-framework ecto

elixir - etimologia - Inserción de modelos asociados en ecto.



phoenix mix routes (2)

Estoy intentando insertar una estructura de factura junto con sus elementos de factura asociados. Puedo insertar los datos de la factura y llamar a una función anónima para validar, emitir e insertar cada elemento. Dado que insert / 2 no produce una devolución, ¿cómo puedo obtener el invoice_id para los artículos mientras todavía puedo revertir la transacción completa si un artículo falla la validación o la inserción?

He puesto el código en mi propio repositorio, aquí está:

def insertassoc(params) do Repo.transaction(fn -> i = Invoice.changeset(params["data"], :create) if i.valid? do Repo.insert(i) else Repo.rollback(i.errors) end insert_include = fn k -> c = InvoiceItem.changeset(k, :create) if c.valid? do Repo.insert(c) else Repo.rollback(c.errors) end end for include <- params["includes"] do insert_include.(Map.merge(include, %{"invoice_id" => ????})) end end) end

y aquí es cómo lo uso desde mi controlador:

def create(conn, params) do case InvoiceRepo.insertassoc(params) do {:ok, x} -> json conn, Map.merge(params, %{"message" => "OK"}) {:error, x} -> json conn |> put_status(400), Map.merge(params, %{"message" => "Error"}) end end

No hay muchos ejemplos actualizados con Ecto, así que disculpe si estas son preguntas noob ;-). ¿Alguien tiene una idea? Intenté colocar la inserción de facturas en una función privada y usar un bloque de casos para determinar si la transacción principal debería revertirse, pero tampoco pude averiguar cómo obtener la identificación de la factura.


En Ecto 2.0 estarías haciendo algo como:

%My.Invoice{} |> Ecto.Changeset.change |> Ecto.Changeset.put_assoc(:invoice_items, [My.InvoiceItem.changeset(%My.InvoiceItem{}, %{description: "bleh"})]) |> My.Repo.insert!

(La respuesta aceptada funciona pre 2.0, también, Valim menciona en los comentarios de esa respuesta de la existencia de put_assoc )


Repo.insert/1 realidad devuelve el modelo que acaba de insertar. También desea desacoplar la validación del manejo de transacciones tanto como sea posible. Sugeriría algo como sigue:

invoice = Invoice.changeset(params["data"], :create) items = Enum.map(params["includes"], &InvoiceItem.changeset(&1, :create)) if invoice.valid? && Enum.all?(items, & &1.valid?) do Repo.transaction fn -> invoice = Repo.insert(invoice) Enum.map(items, fn item -> item = Ecto.Changeset.change(item, invoice_id: invoice.id) Repo.insert(item) end) end else # handle errors end