Ruby on Rails: Verschachtelte Attribute, belongs_to Beziehung
-
22-09-2019 - |
Frage
ich eine Benutzereinheit, die einen aktuellen Standort Feld (Stadt und Land) hat. Um diese Informationen zu halten habe ich eine Entität namens Stelle, die has_many Benutzer.
Ich bin nicht ganz sicher, ob ich in dem User-Modell „has_one“ oder „belongs_to“ setzen sollte, aber für das, was ich las, wenn ich es wollte, den Fremdschlüssel der Lage haben, soll ich „belongs_to“ setzen. Ich möchte auch in der Lage sein, die Benutzer jetzigen Standort zu bearbeiten, wenn der Benutzer bearbeiten. so ich bin mit verschachtelten Attributen. Aber wenn ich den Benutzer bearbeiten ich am Ende das Hinzufügen eines neuen Ort jedes Mal, ohne jemals es dem Benutzer zuordnet, die bearbeitet wurde. Kannst du mir helfen?
Mein Code ist die folgende:
#User Model
class User < ActiveRecord::Base
## Relationships
belongs_to :current_location, :class_name => 'Location'
accepts_nested_attributes_for :current_location
end
#Location Model
class Location < ActiveRecord::Base
#Relationship
has_many :users
end
# part of the _form_edit.haml
- form_edit.fields_for :current_location do |location_form|
= location_form.label :location, "Current Location"
= location_form.text_field :location
#Application Helper
#nested attributes for user and location
def setup_user(user)
returning(user) do |u|
u.build_current_location if u.current_location.nil?
end
end
#in the user controller (added after edit)
def update
@user = @current_user
if @user.update_attributes(params[:user])
flash[:notice] = "Account updated!"
redirect_to account_url
else
render :action => :edit
end
end
Lösung
Das genaue Problem Sie konfrontiert, wie andere haben darauf hingewiesen, dass der Controller nicht den Standort-ID empfängt, wie es sollte. Sieht aus mir der Lage-ID wird durch die falschen Parameter übergeben. Leider ist ein Standort-ID nicht auf einen neuen Datensatz vorhanden ist, so dass dieses in der Form nicht möglich ist.
Ihr Problem ergibt sich aus der Verwendung accepts_nested_attributes_for auf einem belongs_to Beziehung. Das Verhalten ist nicht klar definiert. Dies scheint ein Fehler dokumentiert werden. So ist die accepts_nested_attributes_for sollte auf einer Eins hat oder viele Seiten eine Beziehung hat.
Hier sind einige mögliche Lösungen:
-
Move The accepted_nested_attributes_for zum Ort Modell und bauen Sie Ihre Formen umgekehrt.
-form_for @location do |location_form| ... =location_form.fields_for @user do |user_form| ....
Leider ist dies nicht für eine logische Art und Weise zu ermöglichen, Informationen zu präsentieren. Und macht die Bearbeitung der richtigen Benutzer schwierig.
-
Verwenden Sie verbinden ein Modell und machen eine hat ein:. Durch Beziehung
Ich bin ehrlich gesagt nicht sicher, wie gut accept_nested_attributes_for Arbeiten mit ein: durch Beziehung, aber es wird auf jeden Fall Ihr Problem lösen mit Datensätzen verknüpfen
.
-
Ignorieren accepts_nested_attributes_for und die Zuordnung in Ihrem Controller auf die altmodische Art und Weise handhaben.
halten eigentlich die accepts_nested_attributes_for. Es bietet einige praktische Bequemlichkeit Methoden, nur um es zu dem update_attributes / create-Anweisung nicht bekommen lassen.
def update @user = @current_user completed = false location_params = params[:user].delete(:current_location_attributes) User.transaction do @location = Location.find_or_create_by_id(location_params) @user.update_attributes(params[:user]) @user.current_location = @location @user.save! completed = true end if completed flash[:notice] = "Account updated!" redirect_to account_url else render :action => :edit end end
Felder für wird ein ID-Feld in dem current_location_attributes Hash automatisch ausgefüllt, wenn es nicht einen neuen Standort zu schaffen. Allerdings find_or_create_by_id, erfordert ein: id Eintrag in der Hash für sie zu arbeiten. Es wird mit einer korrekt Auto erhöhte ID erstellen, wenn die ID nicht in der Datenbank ist. Wenn Sie einen neuen Standort erstellen müssen Sie es hinzufügen. Einfachste es in die Form mit =location_form.hidden_field :id, 0 unless current\_location.new\_record?
hinzuzufügen.
Allerdings möchten Sie vielleicht auf doppelte Lage Schöpfung zu reduzieren, und die Location.find_or_create_by_id Linie zu Location.find_or_create_by_location ändern. Dies wird auch auf die Fehler von Fehlern bei Einzigartigkeit Validierungen abgeholzt.
Andere Tipps
Sie bieten nicht die ID des verschachtelten Attribut. So Schienen denkt, es ist ein neues Geschäft.
- form_edit.fields_for :current_location do |location_form|
= location_form.label :location, "Current Location"
= location_form.text_field :location
= location_form.hidden_field :id unless location_form.new_record?
Nicht sicher, ob die vorherige Antwort wirklich korrekt ist. Was Sie brauchen, ist die ID des Benutzers für den Standort angeben, nicht die Lage selbst.
- form_edit.fields_for :current_location do |location_form|
= location_form.label :location, "Current Location"
= location_form.text_field :location
= location_form.hidden_field :user_id
In der Standardeinstellung belongs_to :current_location, :class_name => 'Location'
erwarten, dass die Users
Tabelle ein current_location_id
Feld hat. Sobald Sie diese haben sollten Sie in der Lage sein, etwas zu tun:
@user = @current_user
@user.update_attributes(params[:user])
@location = @user.current_location or @user.build_current_location
@location.update_attributes(params[:location])
@user.current_location.save!
@user.save!