web-dev-qa-db-fra.com

Quand ActiveRecord enregistrera-t-il les associations?

1) Je sais que cela sauvera les associations lorsque autosave: true selon http://railsapi.com/doc/Rails-v2.3.8/classes/ActiveRecord/AutosaveAssociation.html

2) Je sais que cela sauvera des associations qui se construisent comme

book = Book.new(name: 'foo')
book.authors.build(name: 'bar') #has_many
book.save

ou comme

book = Book.new(name: 'foo')
book.build_author(name: 'bar') #has_one
book.save

3) Je pense que les associations sont également enregistrées lorsqu'elles sont attribuées ou ajoutées

book = Book.new(name: 'foo')
book.author = Author.new(name: 'bar')
book.save

ou

book = Book.new(name: 'foo')
book.authors << Author.new(name: 'bar')
book.save

Mais, j'ai un bug compliqué qui implique quelque chose qui ne se sauvegarde pas automatiquement quand je m'y attendais. Donc, je veux déboguer en inspectant book pour vérifier ce que je pense qui va être enregistré sera effectivement enregistré.

TL; DR; Quel état interne est vérifié lors de l'enregistrement des associations? Je suppose qu'un modèle a une variable d'instance interne comme associations_to_save auquel les associations s'ajoutent lors de leur création. Ensuite, lorsque le modèle est enregistré, il parcourt ces associations et les enregistre également.

34
hrdwdmrbl

Malheureusement, il n'y a rien de tel que associations_to_save. Cependant, il existe des règles indiquant ce qui est sauvegardé quand. Vous pouvez les trouver ici: http://guides.rubyonrails.org/association_basics.html . Points: 4.1.5 (appartient_à), 4.2.5 (has_one), 4.3.4 (has_many) et 4.4.4 (habtm).

MISE À JOUR:

En cas d'association has_many, l'enfant est enregistré lors de l'enregistrement du parent si child.new_record? renvoie true (l'enfant n'a pas encore été enregistré dans db) ou la colonne foreign_key doit être mise à jour. C'est pourquoi:

  1. L'ajout d'un objet à l'association sur le parent enregistré enregistre le nouvel enfant.
  2. L'ajout d'un objet à l'association sur un parent non enregistré n'est pas enregistré (pas de valeur de clé étrangère)
  3. Si un parent non enregistré est enregistré et que certains objets enfants sont dans le cache d'association, ces objets sont enregistrés pour mettre à jour foreign_key.
27
BroiSatse

Je ne sais pas si cela aidera quelqu'un d'autre, mais j'ai récemment rencontré un problème similaire récemment dans Rails 5.2.

Lorsque j'essayais d'enregistrer un objet à 2 couches de profondeur, mes tests ont échoué si les objets de niveau supérieur et de premier niveau avaient déjà été enregistrés. C'est à dire.

book_cover.persisted? == true
book_cover.book.persisted? == true

page = book_cover.book.pages.new

page.persisted? == false

# After saving the top level object
book_cover.save
page.persisted? == false

# After saving the immediate parent of page
book_cover.book.save
page.persisted? == true

Étant donné que la "couverture de livre" parent n'était pas le parent direct du nouvel objet "page", l'enregistrement de la "couverture de livre" n'a pas fini par enregistrer l'objet "page".

Selon la situation, je viens d'appeler explicitement save sur l'objet "book" pour sauvegarder tous les objets enfants.

2
Matt H