2016-03-18 7 views
9

Ich habe ein Abonnement wie folgt.Wie aktualisiere ich eine Beziehung in Ecto?

defmodule Rebirth.Subscription do 
    use Rebirth.Web, :model 

    schema "subscriptions" do 
    ... 
    belongs_to :user, Rebirth.User 
    ... 
    end 

    ... 

    def update_user(model, params \\ :empty) do 
    model 
    |> cast(params, @required_fields, @optional_fields) 
    |> cast_assoc(:user, required: false)  
    end 
end 

Ich möchte ein Benutzer auf das Abonnement assoziieren

Also habe ich versucht

Rebirth.Subscription.update_user(subscription, %{user_id: 1}) 

oder

Rebirth.Subscription.update_user(subscription, %{user: user}) 

Als ich es betreibe ich die folgende Fehlermeldung erhalten:

** (ArgumentError) unknown assoc `user` in `cast_assoc` 

Wie aktualisiere ich die user_id?

Danke!

+0

Ich habe derzeit das gleiche Problem.:/ –

+0

Ich habe noch keinen Weg gefunden, es zu reparieren, aber ich grabe herum, ich isolierte das Problem auf 'Ecto.Changeset.cast_relation/4'. Insbesondere "Map.get (Typen, Schlüssel)". Die Assoziation gehört nicht zu den Modellen "Typen". –

+0

Nun, meine "es ist mitten in der Nacht und ich bin müde von diesem" Lösung ist die "Cast_assoc" zu entfernen und 'user_id' zu der Liste der erforderlichen Parameter hinzufügen. Es ist eine anständige temporäre Abhilfe. –

Antwort

11

cast_assoc auf „Cast zugeordnet Modell“ verwendet und kann nur mit has_one und has_many verwendet werden. belongs_to relation definiert die ausländische ID in dem Modell, in dem sie aufgerufen wird. has_many und has_one verlassen sich auf "das andere" Objekt mit Fremdschlüssel.

Wenn Sie Objekte erstellen, die viele andere Objekte haben, ist es sinnvoll, alle zu überprüfen, ob sie gültig sind. cast_assoc ruft cast in ihren jeweiligen Modulen auf.

Ihr Benutzer kann viele Abonnements haben (wahrscheinlich, rate ich hier), so ist es nicht sinnvoll, Benutzer beim Erstellen des Abonnements zu erstellen und zu überprüfen, ob der Benutzer über cast_assoc gültig ist. In diesem Fall existiert der Benutzer normalerweise bereits in der Datenbank.

In Ihrem Fall, dass Sie nur prüfen, ob im Zusammenhang Modell in der Besetzung vorhanden ist, so sollten Sie verwenden:

|> assoc_constraint(:user) 

Dies lässt sich aber nicht vom Benutzer, sondern prüft, ob gegeben user_id in der Datenbank vorhanden ist. Nun, wenn Sie das Abonnement für einen Benutzer aktualisieren möchten, können Sie dies tun:

user = Repo.get(User, id) 
subscription = Ecto.build_assoc(user, :subscriptions, other_fields_as_map) 

Hinweis erfordert has_one oder has_many auf dem Benutzermodell.

Oder Sie können einfach die Benutzer-ID aktualisieren, wie Sie versuchten vor:

Rebirth.Subscription.update_user(subscription, %{user_id: 1}) 

und dieses Mal wird es die Datenbank überprüfen, ob bestimmte Benutzer-ID vorhanden ist, aber Sie werden nicht Objekt gesamte Benutzer übergeben werden können, Hier.

Und wenn Sie verknüpfte Benutzer aktualisieren möchten, müssen Sie es explizit in zwei Schritten tun. a) Holen Sie den Benutzer, b) Aktualisieren Sie den Benutzer mit Changeset in seinem Modul definiert.

Endgültig, wenn Sie keine separate Validierung für die Aktualisierung von Benutzern machen (und ich denke nicht, dass Sie in diesem Szenario sollten), wäre es gut, die Funktion von update_user zu changeset umzubenennen. Derselbe Changeset kann zum Erstellen und Aktualisieren von Modellen verwendet werden.

+0

Danke! Bedeutet dies, dass die einzige Möglichkeit, den Benutzer für ein Abonnement und nicht für die Abonnements eines Benutzers festzulegen, die Benutzer-ID ist? Wenn ich nicht falsch liege, macht das ein neues Abonnement, richtig: Ecto.build_assoc (user,: subscriptions, other_fields_as_map)? –

+0

Das ist richtig. Es wäre nicht sinnvoll, den Benutzer auf ein Abonnement festzulegen, da dies der Benutzer ist, der viele Abonnements haben kann. Und ja, 'build_assoc' erstellt ein neues Abonnement mit' user_id' set. Dies ist nur eine Kurzform, um die ID zu erhalten und sie im Abonnement manuell zu setzen, auch für Assoziationen. – tkowal