読者です 読者をやめる 読者になる 読者になる

【Rails】多対多のリレーションでhas_and_belongs_to_manyを使って検索する方法メモ

はじめに

今回やりたかったのは2つのテーブルの関連テーブルを設けてそれぞれ紐づいている状態のデータを検索すること。
ありがちなテーブル構造だと思いますが、以下のような形です

・categories(動画のカテゴリー)

idカテゴリーIDPK
nameカテゴリー名

・videos(動画)

id動画IDPK
titleタイトル

・categories_videos(カテゴリー・動画関連)

idIDPK
category_idカテゴリーIDFK
video_id動画IDFK

テーブル作成

ひな形作成

$ 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

idtitle
1動画1

categories

idname
1カテゴリー1
2カテゴリー2

categories_videos

category_idvideo_id
11
21

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", ・・・>]>

ちゃんと双方向から検索ができました。とりあえずやりたかったことはできました、以上です