2017-05-29 2 views
0

Dans mon application Phoenix je les schémas suivants:Ecto.Multi ussage

defmodule TattooBackend.Accounts.Account do 
    schema "accounts" do 
    field :email, :string 
    field :crypted_password, :string 
    field :password, :string, virtual: true 
    field :password_confirmation, :string, virtual: true 

    timestamps() 
    end 
end 

defmodule TattooBackend.Accounts.Studio do 
    schema "studios" do 
    field :name, :string 

    belongs_to :account, Account 

    timestamps() 
    end 
end 

Maintenant, je suis en train d'écrire du code pour insérer compte et le Studio à la base de données en une seule transaction. J'utilise Ecto.Multi pour cela. Mon code ressemble à ceci:

multi = Multi.new |> 
Multi.insert(:account, Account.changeset(%Account{}, %{email: "[email protected]", password: "password", password_confirmation: "password"})) |> 
Multi.run(:studio, fn %{account: account} -> 
    studio_changeset = Studio.changeset(%Studio{}, %{name: "test", account_id: account.id}) 
    Repo.insert(studio_changeset) 
end) 

Repo.transaction(multi) 

Ce code fonctionne parfaitement bien, mais je me demande s'il y a un endroit pour le rendre meilleur. Je suis encore assez nouveau à Elixir donc je veux savoir si quelque chose peut être fait de meilleure façon. Merci d'avance.

+1

Y a-t-il une raison particulière pour laquelle vous utilisez 'Multi.run/3' au lieu d'un' Multi.insert/4'? –

+0

@JustinWood J'ai utilisé Multi.run parce que j'ai besoin de mettre à jour la valeur de modification du compte de Studio après la création du compte. Ou peut-être y at-il moyen de le faire en utilisant Multi.insert? –

+1

Vous avez raison. Je n'ai pas réalisé que vous ne pouviez pas obtenir les changements en cours avec 'Multi.insert/4'. –

Répondre

1

Pour ce code particulier, vous utilisez put_assoc pour mettre la nouvelle Studio dans Account puis faire Repo.insert!:

Account.changeset(%Account{}, %{email: "[email protected]", password: "password", password_confirmation: "password"}) 
|> Ecto.Changeset.put_assoc(:studios, [Studio.changeset(%Studio{}, %{name: "test"})]) 
|> Repo.insert! 

put_assoc se chargera de mettre le account_id correct dans le Studio avant qu'il ne soit inséré et les deux inserts seront également être exécuté automatiquement dans une transaction.

+0

Le code suivant: '' 'Account.changeset (% Account {},% {email:" [email protected] ", mot de passe:" password ", password_confirmation:" mot de passe "}) |> Ecto.Changeset.put_assoc (: studio, [Studio.changeset (% Studio {},% {name: "test"})]) |> Repo.insert '' ' Retourne l'erreur: ** (FunctionClauseError) aucune correspondance de clause de fonction dans anonyme fn/2 dans Ecto.Changeset.get_changed/6 –

+1

Est-ce que 'Account' a' has_many: studios, TattooBackend.Accounts.Studio'? Si ce n'est pas le cas, veuillez essayer d'ajouter cela, puis changer ': studio' en': studios' dans 'put_assoc'. – Dogbert

+0

'Account' a' has_one: studio, Studio' –