-
Notifications
You must be signed in to change notification settings - Fork 0
Les associations en Rails: Partie 03
Bouzid Badreddine edited this page Oct 15, 2020
·
2 revisions
Dans la leçon précédente on a vu comment accéder au livre associé à l'auteur à partir de l'auteur directement, en utilisant has_one
.
Si l'auteur peut avoir plusieurs livres, il serait convenable de pouvoir y accéder (aux livres) à partir des objets Author
, pour les lires et les modifier. Cela est possible en utilisant has_many
.
Il suffit d'appeler la méthode has_many
dans la classe Author
avec comme argument un symbole représentant le modèle Book
en pluriel (remarquez la différence avec has_one :book
, singulier).
class Author < ApplicationRecord
has_many :books
end
Maintenant on peut attribuer plusieurs livres à un auteur directement à partir des instances de Author
:
2.4.0 :003 > ahmed = Author.new name: "Ahmed"
=> #<Author id: nil, name: "Ahmed", created_at: nil, updated_at: nil>
2.4.0 :004 > book1 = Book.new title: "Quantum Mechanics"
=> #<Book id: nil, title: "Quantum Mechanics", author_id: nil, created_at: nil, updated_at: nil>
2.4.0 :005 > book2 = Book.new title: "Algebra"
=> #<Book id: nil, title: "Algebra", author_id: nil, created_at: nil, updated_at: nil>
2.4.0 :006 > book1.valid?
=> false
2.4.0 :007 > book1.errors.messages
=> {:author=>["must exist"]}
2.4.0 :009 > ahmed.valid?
=> true
2.4.0 :010 > ahmed.books
=> #<ActiveRecord::Associations::CollectionProxy []>
2.4.0 :011 > ahmed.books.size
=> 0
2.4.0 :012 > ahmed.books << book1
=> #<ActiveRecord::Associations::CollectionProxy [#<Book id: nil, title: "Quantum Mechanics", author_id: nil, created_at: nil, updated_at: nil>]>
2.4.0 :013 > ahmed.books.size
=> 1
2.4.0 :014 > ahmed.books.count
=> 0
2.4.0 :015 > ahmed.books << book2
=> #<ActiveRecord::Associations::CollectionProxy [#<Book id: nil, title: "Quantum Mechanics", author_id: nil, created_at: nil, updated_at: nil>, #<Book id: nil, title: "Algebra", author_id: nil, created_at: nil, updated_at: nil>]>
2.4.0 :016 > ahmed.books.size
=> 2
2.4.0 :017 > ahmed.books.count
=> 0
2.4.0 :018 > ahmed.save
(0.2ms) begin transaction
SQL (1.4ms) INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Ahmed"], ["created_at", "2017-07-13 11:23:47.766572"], ["updated_at", "2017-07-13 11:23:47.766572"]]
SQL (0.2ms) INSERT INTO "books" ("title", "author_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "Quantum Mechanics"], ["author_id", 1], ["created_at", "2017-07-13 11:23:47.771789"], ["updated_at", "2017-07-13 11:23:47.771789"]]
SQL (0.1ms) INSERT INTO "books" ("title", "author_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "Algebra"], ["author_id", 1], ["created_at", "2017-07-13 11:23:47.772789"], ["updated_at", "2017-07-13 11:23:47.772789"]]
(119.4ms) commit transaction
=> true
2.4.0 :019 > ahmed.books.size
=> 2
2.4.0 :020 > ahmed.books.count
(0.5ms) SELECT COUNT(*) FROM "books" WHERE "books"."author_id" = ? [["author_id", 1]]
=> 2
2.4.0 :021 > book1.reload.author.name
Book Load (0.7ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> "Ahmed"
2.4.0 :022 > ahmed.reload.books.first.title
Author Load (0.3ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Book Load (0.5ms) SELECT "books".* FROM "books" WHERE "books"."author_id" = ? ORDER BY "books"."id" ASC LIMIT ? [["author_id", 1], ["LIMIT", 1]]
=> "Quantum Mechanics"
2.4.0 :023 > ahmed.reload.books.second.title
Author Load (0.4ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Book Load (0.5ms) SELECT "books".* FROM "books" WHERE "books"."author_id" = ? ORDER BY "books"."id" ASC LIMIT ? OFFSET ? [["author_id", 1], ["LIMIT", 1], ["OFFSET", 1]]
=> "Algebra"
Plusieurs remarques s'imposent:
- Il y a un différence entre la méthode
size
et la méthodecount
,size
retourne la taille de la liste.books
alors quecount
retourne le nombre de ces livres en faisant une requête dans la base de données (ou en puisant dans la cache quand c'est possible). Avant la sauvegardesize
donnait un nombre non nul alors quecount
donnait 0. Après la sauvegarde tout deux donnaient la même valeur. -
.books
se comporte maintenant plus comme un array, c'est pour cela qu'on a pu appeler.size
et<<
sur lui. - La sauvegarde d'un objet enclenche la sauvegarde des objets qui lui sont associés.