Question

J'ai une entité utilisateur qui a un champ Emplacement actuel (ville et pays). Pour tenir cette information que j'ai créé une entité appelée Lieu qui has_many utilisateurs.

Je ne suis pas tout à fait sûr que je devrais mettre dans le modèle utilisateur « has_one » ou « belongs_to », mais pour ce que je lis si je voulais qu'il ait la clé étrangère de l'endroit que je devrais mettre « belongs_to ». Je veux aussi pouvoir modifier emplacement actuel de l'utilisateur lors de l'édition l'utilisateur. donc je suis en utilisant les attributs imbriqués. Mais quand je modifier l'utilisateur, je finis par l'ajout d'un nouvel emplacement à chaque fois sans jamais l'associer à l'utilisateur qui a été édité. Peux-tu m'aider?

Mon code est le suivant:

#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
Était-ce utile?

La solution

Le problème exact que vous êtes confronté, comme d'autres l'ont souligné est que le contrôleur ne reçoit pas l'identifiant de l'emplacement comme il se doit. Ressemble me l'identifiant de l'emplacement est passé à travers le mauvais paramètre. Malheureusement, un identifiant de localisation n'existe pas sur un nouveau record, donc ce n'est pas possible sous la forme.

Votre problème vient du accepts_nested_attributes_for d'utilisation sur une relation de belongs_to. Le comportement est pas clairement défini. Cela semble être un bogue documenté. Ainsi, le accepts_nested_attributes_for devrait être sur a un ou a beaucoup d'autre d'une relation.

Voici quelques solutions possibles:

  1. Déplacer le accepted_nested_attributes_for au modèle de localisation et de construire vos formulaires dans l'autre sens.

    -form_for @location do |location_form|
     ...
     =location_form.fields_for @user do |user_form|
       ....
    

    Malheureusement, cela ne permet pas une façon logique de présentation de l'information. Et rend l'édition de l'utilisateur droit difficile.

  2. Utilisez une jointure modèle, et faire un a un. Par rapport

    Je suis honnêtement ne sais pas comment fonctionne accept_nested_attributes_for avec: à travers une relation, mais cela certainement résoudre votre problème avec couplage des enregistrements

  3. .
  4. Ignorer accepts_nested_attributes_for et de gérer l'association dans votre contrôleur à l'ancienne.

    En fait garder le accepts_nested_attributes_for. Il fournit des méthodes pratiques à portée de main, ne laissez pas arriver à les update_attributes / create.

    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
    

Les champs pour se remplir un champ id dans le hachage current_location_attributes automatiquement, si elle ne crée pas un nouvel emplacement. Cependant, find_or_create_by_id, nécessite une: entrée id dans le hachage pour que cela fonctionne. Il va créer un identifiant correctement incrémentée automatique si l'ID est pas dans la base de données. Si vous créez un nouvel emplacement, vous devez l'ajouter. Pour l'ajouter facile à la forme avec =location_form.hidden_field :id, 0 unless current\_location.new\_record?.

Cependant, vous pouvez réduire la création de l'emplacement en double, et changer la ligne Location.find_or_create_by_id à Location.find_or_create_by_location. Cela permettra également de réduire les erreurs de l'unicité échec de validation.

Autres conseils

Vous ne fournissez pas l'identifiant de l'attribut imbriqué. Alors rails pense qu'il est un nouveau.

- 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?

Je ne sais pas si la réponse précédente est vraiment correcte. Ce que vous avez besoin est de spécifier l'ID de l'utilisateur pour l'emplacement, pas l'emplacement lui-même.

- 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

Par belongs_to :current_location, :class_name => 'Location' par défaut attendre la table Users ont un champ de current_location_id. Une fois que vous avez cela, vous devriez être en mesure de faire quelque chose comme:

@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!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top