【Rails】多対多のリレーションでhas_and_belongs_to_manyを使って検索する方法メモ
はじめに
今回やりたかったのは2つのテーブルの関連テーブルを設けてそれぞれ紐づいている状態のデータを検索すること。
ありがちなテーブル構造だと思いますが、以下のような形です
・categories(動画のカテゴリー)
id | カテゴリーID | PK |
---|---|---|
name | カテゴリー名 |
・videos(動画)
id | 動画ID | PK |
---|---|---|
title | タイトル |
・categories_videos(カテゴリー・動画関連)
id | ID | PK |
---|---|---|
category_id | カテゴリーID | FK |
video_id | 動画ID | FK |
テーブル作成
ひな形作成
$ rails g model Video $ rails g model Category $ rails g model CategoryVideo
テーブル定義設定
db/migrate/xxxx_create_videos.rb
class CreateVideo < ActiveRecord::Migration[5.0] def change create_table :videos do |t| t.string :name t.timestamps end end end
db/migrate/xxxx_create_categories.rb
class CreateCategory < ActiveRecord::Migration[5.0] def change create_table :categories do |t| t.string :title t.timestamps end end end
db/migrate/xxxx_create_category_videos.rb
class CreateCategoryVideos < ActiveRecord::Migration[5.0] def change create_table :categories_videos do |t| ## ★テーブル名がcategory_videosだったのを変更 t.integer :category_id t.integer :video_id t.timestamps end end end
マイグレーション実行
$ rake db:migrate
Model設定
app/models/category.rb
class Category < ApplicationRecord has_and_belongs_to_many :videos end
app/models/videos.rb
class Video < ApplicationRecord has_and_belongs_to_many :categories end
実際に検索してみる
videos
id | title |
---|---|
1 | 動画1 |
categories
id | name |
---|---|
1 | カテゴリー1 |
2 | カテゴリー2 |
categories_videos
category_id | video_id |
---|---|
1 | 1 |
2 | 1 |
videos => categories_videos => categoriesへのjoin
> videos = Video.includes(:categories) Video Load (22.2ms) SELECT `videos`.* FROM `videos` HABTM_Categories Load (3.8ms) SELECT `categories_videos`.* FROM `categories_videos` WHERE `categories_videos`.`video_id` IN (1) Category Load (0.7ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (1, 2) ・・・ > videos[0].categories => #<ActiveRecord::Associations::CollectionProxy [#<Category id: 1, name: "カテゴリー1", ・・・>, #<Category id: 2, name: "カテゴリー2", ・・・>]>
categories => categories_videos => videosへのjoin
> categories = Category.includes(:videos) Category Load (0.7ms) SELECT `categories`.* FROM `categories` HABTM_Videos Load (0.6ms) SELECT `categories_videos`.* FROM `categories_videos` WHERE `categories_videos`.`category_id` IN (1, 2) Video Load (0.6ms) SELECT `videos`.* FROM `videos` WHERE `videos`.`id` = 1 ・・・ > categories[0].videos => #<ActiveRecord::Associations::CollectionProxy [#<Video id: 1, title: "動画1", ・・・>]>
ちゃんと双方向から検索ができました。とりあえずやりたかったことはできました、以上です