[Rails]has_manyで追加されるメソッドの中で、今まで知らなかったメソッドを触ってみる
1. はじめに
初めまして、Open8でバックエンドエンジニアをやっているハガと申します。
Railsの知見を深めるために、今回はhas_manyで追加されるメソッドの中で、今まで知らなかったメソッドを触ってみようと思いますー!
2. (ざっくりおさらい)Railsのアソシエーションとは何か
タイトルの件に入る前に、Railsのアソシエーションについてざっくりおさらいしようと思います。
Railsのアソシエーションとは、ActiveRecordモデル間の繋がりのことです。
モデル間にアソシエーションを設定することで、モデル間の操作をシンプルに操作できるメソッドが自動で定義されたり、アプリケーション側でモデル間のデータに不整合がないかをチェックできます。
モデル間にアソシエーションを設定するためには、has_many
やbelogns_to
などを利用して明示的にアソシエーションの設定を宣言する必要があります。
2.1 アソシエーションを設定しない場合
class Author < ApplicationRecord
end
class Book < ApplicationRecord
end
既存の著者の新しい書籍を作成する場合、以下のようなコードを書く必要があります。
@book = Book.create(published_at: Time.now, author_id: @author.id)
ある1人の著者を削除して、その著者に紐づく書籍も削除する場合、以下のようなコードを書く必要があります。
@books = Book.where(author_id: @author.id)
@books.each do |book|
book.destroy
end
@author.destroy
2.2 アソシエーションを設定した場合
class Author < ApplicationRecord
has_many :books, dependent: :destroy
end
class Book < ApplicationRecord
belongs_to :author
end
既存の著者の新しい書籍を作成する場合、以下のようにシンプルにかけます。
@book = @author.books.create(published_at: Time.now)
ある1人の著者を削除して、その著者に紐づく書籍も削除する場合、以下のようにシンプルにかけます。
@author.destroy
アソシエーションを設定することでモデル間の操作がシンプルになって扱いやすくなったことが分かりました。
アソシエーションについてより詳細に知りたい場合はRailsガイドに載っているので、そちらを参照していただけるようお願いします。
3. has_manyで追加されるメソッドの中で、今まで知らなかったメソッドを触ってみる
3.1 collection_singular_ids
collection_singular_ids
メソッドは、コレクションに含まれるオブジェクトのidの集合を配列として返してくれます。
collection_singular_idsのcollection_singularとは、 has_many: users
を定義した際のuser
という単数形を指しています。collection_singular_ids
は、以下のコード例の場合だとuser_ids
にあたります。
関連先のidの集合だけ欲しい場合に使えるなと思いました。
irb(main):006:0> organization = Organization.first
Organization Load (6.0ms) SELECT `organizations`.* FROM `organizations` ORDER BY `organizations`.`id` ASC LIMIT 1
=>
#<Organization:0x0000ffff6fa88df0
...
irb(main):007:0> organization.user_ids
(3.9ms) SELECT `users`.`id` FROM `users` WHERE `users`.`organization_id` = 1
=> [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44]
3.2 collection.exists?(...)
collection.exists?メソッドは、指定された条件に一致するオブジェクトがコレクションの中に存在するかをチェックして、真偽値を返します。
collection.exists?のcollectionとは、has_many: users
を定義した際のusers
という複数形を指しています。collection.exists?
は、以下のコード例の場合だとusers.exists?
にあたります。
関連先のモデルが存在するかどうかで条件分岐したい時に使えるなと思いました。
irb(main):010:0> organization.users.exists?(deleted_at: nil)
User Exists? (5.8ms) SELECT 1 AS one FROM `users` WHERE `users`.`organization_id` = 1 AND `users`.`deleted_at` IS NULL LIMIT 1
=> true
3.3 collection.create!(attributes = {})
このメソッド自体は知っていたのですが、複数個オブジェクトを生成することもできるようです。
organization_idをuserにセットする手間を省けて、複数個のオブジェクトを生成できるので、便利です。
organization.users.create([
{ name: "hoge" },
{ name: "fuga" },
])
4. まとめ
アソシエーションについて、まだまだ知らないメソッドがあるので、また近いうちに学習しようと思いますー!
5. 参考記事
株式会社オープンエイトのテックブログです!カジュアル面談大歓迎ですー!エンジニア積極採用中 👉 open.talentio.com/r/1/c/open8/homes/3396
Discussion