Schienen: Auf has_one-Zuordnung erstellen


100

Hallo (großer Rails-Neuling hier), ich habe folgende Modelle:

class Shop < ActiveRecord::Base
  belongs_to :user
  validates_uniqueness_of :title, :user_id, :message => "is already being used"
end

und

class User < ActiveRecord::Base
  has_one :shop, :dependent => :destroy
end

Wenn ich einen neuen Shop erstellen möchte, wird folgende Fehlermeldung angezeigt:

private method `create' called for nil:NilClass

Das ist mein Controller:

@user = current_user
@shop = @user.shop.create(params[:shop])

Ich habe verschiedene Variationen ausprobiert, indem ich hier und da Anleitungen und Tutorials gelesen habe, aber ich bin verwirrter als zuvor und kann es nicht zum Laufen bringen. Jede Hilfe wäre sehr dankbar.


Der Titel der Frage wurde bearbeitet, um die Frage wiederzugeben. Duplikat der Verwendung von Build mit einer has_one-Zuordnung in Schienen
Marc-André Lafortune

1
Sie können auch verwenden@user.build_shop(params)
ImranNaqvi

Antworten:


123

Hier erfahren Sie zunächst, wie Sie das tun, was Sie wollen:

@user = current_user
@shop = Shop.create(params[:shop])
@user.shop = @shop

Hier ist der Grund, warum Ihre Version nicht funktioniert hat:

Sie dachten wahrscheinlich, dass dies funktionieren könnte, denn wenn der Benutzer eine has_manyBeziehung zu Shop @user.shops.create(params[:shop]) hätte , würde dies funktionieren. Es gibt jedoch einen großen Unterschied zwischen has_manyBeziehungen und has_oneBeziehungen:

Gibt mit einer has_manyBeziehung shopsein ActiveRecord-Auflistungsobjekt zurück, das Methoden enthält, mit denen Sie einem Benutzer Shops hinzufügen und daraus entfernen können. Eine dieser Methoden besteht darin create, einen neuen Shop zu erstellen und dem Benutzer hinzuzufügen.

Mit einer has_oneRelation erhalten Sie kein solches Sammlungsobjekt zurück, sondern einfach das Shop-Objekt, das dem Benutzer gehört - oder null, wenn der Benutzer noch keinen Shop hat. Da weder Shop-Objekte noch Null eine createMethode haben, können Sie creatediese Methode nicht für has_oneBeziehungen verwenden.


Danke für deine Antwort, sepp2k. Ich sehe jetzt, warum mein Code nicht funktionieren konnte.
Neko

118
Sie könnten auch verwenden @user.create_shop(params[:shop]). Siehe von has_one hinzugefügte Methoden .
Nates

Die gewählte Antwort funktioniert, aber die @ nates-Lösung funktioniert auch. +1 an euch beide.
nfriend21

+1 auf die Antwort, weil ich mich das gleiche gefragt habe, +1 auf die Antwort, um zu erklären, warum dies so ist, und +1 auf den Kommentar, um die beste Lösung zu finden.
Deivid

223

Eine präzisere Möglichkeit, dies zu tun, ist:

@user.create_shop(params[:shop])

Siehe die von has_one hinzugefügten Methoden in den Ruby on Rails- Handbüchern .


6
Dies ist definitiv besser Ansatz
Magnum

7
Beachten Sie, dass bei mehrmaligem Erstellen von "shop_shop" der vorherige Shop gelöscht wird. Wenn Sie @user.create_shop(params[:shop_one_info])es beispielsweise ausführen , wird shop_one erstellt, ABER wenn Sie es ausführen @user.create_shop(params[:shop_two_info]), wird der erste Shop gelöscht und der zweite erstellt.
ecoding5

Der obige Kommentar zum Löschen des vorherigen Shops bezieht sich auf Rails 3.2.18. Sie kennen keine neueren Versionen. Kommentar kann nach 5 min nicht bearbeitet werden -_-
ecoding5

Ich habe eine Lösung gefunden und keine Eindeutigkeit für das zugehörige Modell festgelegt. Stellen Sie daher sicher, dass Sie die Einstellungen im Shop-Modell dieses Beispiels vornehmen.
ecoding5

Sie können auch verwenden@user.build_shop(params)
ImranNaqvi

7

Zwei weitere Möglichkeiten, wenn Sie möchten, saveanstatt create:

shop = @user.build_shop
shop.save

shop = Show.new
shop.user = @user
shop.save

1

Nur um die obigen Antworten zu ergänzen -

@user.create_shop(params[:shop])

Die obige Syntax erstellt einen neuen Datensatz, löscht jedoch anschließend einen ähnlichen vorhandenen Datensatz.

Alternativ, wenn Sie keinen Rückruf zum Löschen auslösen möchten

Shop.create(user_id: user.id, title: 'Some unique title')

Dieser Thread könnte hilfreich sein. Klicke hier

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.