2017-10-11 3 views
1

J'ai une application de blog dans laquelle, quand quelqu'un met à jour un article, il ajoute une entrée dans la table de discussion. Les Post et Newsfeed schémas sont les suivants:Problème lors de la mise à jour d'un enregistrement avec Ecto.Multi

mix phx.new.json Content Post posts title:string content:string 
mix phx.new.json Content Newsfeed newsfeeds message:string 

Voici la fonction enveloppe:

def updateContent(%{id: id, content: content}, _info) do 
    post = Repo.get(post, id) 
    Content.update_content_and_add_to_newsfeed(post, %{id: id, content: content}) 
    end 

Et est la logique ici dans le contexte Contenu:

def update_content_and_add_to_newsfeed(post, %{id: id, content: content}) do 
    multi = 
     Multi.new 
     |> Multi.update(:post, update_post(post, %{content: content})) 
     |> Multi.insert(:newsfeed, %Newsfeed{message: "post updated"}) 

    case Repo.transaction(multi) do 
     {:ok, %{post: post}} -> 
     {:ok, post} 
     {:error, _} -> 
     {:error, "Error"} 
    end 
    end 

Voici le update_post Fonction:

def update_post(%Post{} = post, attrs) do 
    post 
    |> Post.changeset(attrs) 
    |> Repo.update() 
    end 

Quand je lance ce code, les mises à jour de contenu dans la base de données, mais aucun élément de fil d'actualité est insérée, et je vois ce message d'erreur dans la console:

Server: localhost:4000 (http) 
Request: POST /graphiql 
** (exit) an exception was raised: 
    ** (FunctionClauseError) no function clause matching in Ecto.Multi.update/4 

Toute idée de comment résoudre ce problème? J'utilise v2.2.6 et 1.3 avec Absinthe.

+1

Cela pourrait avoir à faire avec vous en utilisant '{: erreur, _}' au lieu de '{: erreur, _, _, _}'. Aussi pouvez-vous poster votre code pour la méthode 'update_post'? – Sheharyar

+0

Voir la mise à jour ci-dessus –

Répondre

1

Votre appel Multi.update/4 est incorrect car il attend un ensemble de modifications. Au lieu de cela, vous mettez à jour votre Post en dehors de la transaction et lui transmettez le résultat de votre mise à jour. Rappelez-vous, le but d'une transaction est de revenir en arrière en cas d'erreur. Cela signifie qu'en cas d'échec, tous les changements doivent être inversés (ce qui ne se produit pas dans votre cas).


Supprimer votre méthode update_post, et au lieu juste passer le changeset:

multi = 
    Multi.new 
    |> Multi.update(:post, Post.changeset(post, %{content: content})) 
    |> Multi.insert(:newsfeed, %Newsfeed{message: "post updated"}) 

En outre, si une transaction Ecto.Multi échoue, elle renvoie un tuple d'erreur 4-élément, pas un 2-élément régulier un . Donc changer votre déclaration case comme ceci:

case Repo.transaction(multi) do 
    {:ok, %{post: post}} -> 
    {:ok, post} 
    {:error, _op, _value, _changes} -> 
    {:error, "Error"} 
end