web-dev-qa-db-fra.com

L'attribut imbriqué update_attributes utilise insert plutôt que update

J'ai un utilisateur et une classe de profil imbriquée comme suit:

class User < ActiveRecord::Base
  has_one :profile
  attr_accessible :profile_attributes
  accepts_nested_attributes_for :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
  attr_accessible :name
end

user = User.find(1)
user.profile.id  # => 1
user.update_attributes(profile_attributes: {name: 'some name'})
user.profile.id  # => 2

Je ne comprends pas pourquoi Rails jette l'ancien profil et en crée un nouveau.

En utilisant

user.profile.update_attributes({name: 'some name'})

met à jour le profil actuel comme prévu. Mais dans ce cas, je ne profite pas de includes_nested_attributes_for

Est-ce que quelqu'un sait pourquoi la mise à jour se produit de cette façon? Je préférerais ne pas me retrouver avec une base de données de lignes de profil non connectées à un utilisateur.

27
Jason

J'ai résolu ce problème en ajoutant l'option update_only:

accepts_nested_attributes_for :profile, update_only: true

Maintenant, un nouveau profil est créé uniquement s'il n'en existe pas déjà un.

19
Jason

Pour tous ceux qui ont le même problème dans Rails 4: fields_for ajoute déjà l'ID de vos formulaires imbriqués, mais vous devez autoriser le paramètre: id. J'ai seulement autorisé un paramètre: nom_objet_id et, comme cela ne génère aucune erreur, cela m'a pris un certain temps avant de voir cela dans les journaux du serveur. Espérons que cela aide quelqu'un à perdre moins de temps que moi à ce sujet :)

33
irruputuncu

Si vous vérifiez votre formulaire, vous devez définir l'attribut id dans le hachage d'attribut imbriqué pour votre objet de profil. Si l'ID n'est pas défini, ActiveRecord considère qu'il s'agit d'un nouvel objet.

Par exemple, si un formulaire ERB crée un ensemble de paramètres "utilisateur" avec un hachage de paramètre "profile_attributes" imbriqué pour le profil imbriqué dans l'utilisateur, vous pouvez inclure une valeur cachée pour l'ID de profil, comme suit:

<%= hidden_field "user[profile_attributes][id]", @profile.id %>
23
Winfield

Cela m'a frappé dans une autre version de Rails et je pensais que je vais perdre la tête. Tout en ajoutant update_only => true résolu, je pense que c'est un bogue quelque part dans Rails.

Symptômes dans mon cas: j'obtiendrais l'association avec la propriété includes_to et le nouvel objet imbriqué créé - jusqu'à ce que je régénère la page pour la première fois. Après cela a fonctionné correctement.

Dans mon cas, j'ai ajouté une méthode before_save à ma classe imbriquée et imprimé ce qu'elle a enregistré. J'ai également imprimé les attributs avant d'appeler update_attributes. Le "parent_id" est correctement défini. J'ai également inclus le champ d'identifiant masqué dans le formulaire, sans modification - ce qui était normal car il était déjà inclus à l'aide de fields_for ...

Surprise: j'ai vu un appel de mise à jour générer deux sauvegardes. La première sauvegarde aurait l'identifiant d'objet imbriqué, mais null pour l'identifiant d'appartenance. - donc, cela mettrait à jour l'enregistrement pour qu'il attribue la valeur null à "parent_id". La deuxième sauvegarde aurait le "parent_id" défini mais l'ID d'objet imbriqué serait défini sur null.

Comme je l'ai dit, je l'ai corrigé en ajoutant update_only => true, mais je pense que c'est toujours un bogue.

Je voudrais savoir si les symptômes ci-dessus s'appliquent à votre cas aussi pour confirmer qu'il s'agit d'un bogue.

0
Victors