【初心者・独学者向け】Ruby on Railsで中間テーブルを作成し、多対多を実現する

Ruby on Railsの中間テーブルを利用して多対多の関係を実現する方法を記載します。
多対多で何ができるか?
1記事に関連するカテゴリーを複数持たせたり、 ツイッターのツイートに対して、複数のタグを持たせたり などなどです。
多対多の関係とは?
記事から見るとカテゴリーを複数持っているので、記事に対して、カテゴリーは多になります。
カテゴリーから見ると1カテゴリーに複数の記事が関連しているので、カテゴリーから見ると記事は多になります。 この関係が多対多になります。
ここまでで、あまり理解出来ない方は、PC画面で この記事の上部へスクロールして、パンくずリストをご覧ください。
以下のようなパンくずリストがあり、こちらにマウスを当てると記事カテゴリーへのリンクとなっていますが
現在ご覧になっているこの記事に対して、Ruby on Railsや初心者向けというような複数のカテゴリーが設定されています。
また、パンくずリストのRuby on Railsのカテゴリーを選択すると複数の記事が表示されます
つまりRuby on Railsのカテゴリーに複数の記事が設定されています。
これが多対多の関係になります。
なおデータベース自体の概要が分からない方は以下から 【初心者・独学者向け】データベースとは何かを解説します
中間テーブルとは?
多対多の関係は2つのモデルでは実現出来ないため、 中間テーブルを利用し多対多の関係を実現します。
以下に3つのサンプルテーブルを記載しています。
articleテーブル(記事を投稿するテーブル)
article_id | タイトル |
---|---|
2 | RubyonRailsに関する記事 |
3 | Javaに関する記事 |
categoryテーブル(記事カテゴリーのテーブル)
category_id | タイトル |
---|---|
1 | プログラミング全般 |
2 | RubyonRails |
3 | Java |
category_articleのテーブル(中間テーブル)
category_id | article_id |
---|---|
1 | 2 |
2 | 2 |
1 | 3 |
3 | 3 |
上記の用にcategoryarticleテーブルでcategoryidとarticle_idをレコードで紐付け、多対多の関係を実現します。
上記の例題では、「RubyonRailsに関する記事」を表示すると その記事のパンくずリストに表示されるカテゴリーは 「プログラミング全般」と「RubyonRails」 が表示されます。
なぜかというと categoryarticleのテーブル(中間テーブル)でarticleid=2とcategoryid=1とcategoryid=2の紐づけを行っているからです。
Modelのアソシエーションの関連性設定
マイグレーションファイルは以下の様に記載して、マイグレーションを実行します。
class CreateCategoriesArticles < ActiveRecord::Migration def change create_table :categories_articles do |t| t.integer :category_id t.integer :article_id t.timestamps null: false end end end
その後は中間テーブルのModel(CategoriesArticleModel)を設定します。
CategoriesArticleModelでArticleのModelとCategoryのModelを関連付けます。
class CategoriesArticle < ActiveRecord::Base belongs_to :category, optional: true belongs_to :article, optional: true end
Rails5からデフォルトで外部キーのnilが許可されなくなったので、 nilを許可する場合は以下のようにbelongs_to へoptional: trueを設定する必要があります。
サンプルコードなので記載していませんが、外部キー設定をお願いします。
次はArticleModelの設定です。
class Article < ActiveRecord::Base has_many :categories_articles has_many :categories, through: :categories_articles end
中間テーブルを通して繋がっているものには through: : categories_articlesというkeyをつけます。
throughオプションによりarticles経由でcategoryにアクセスできるようになります。
上記設定で、articles.categories_articlesで記事に関連するカテゴリーを取得できます。
次はCategoryModelの設定です。
class Category < ActiveRecord::Base has_many :categories_articles has_many :articles, through: :categories_articles end
Articleと同様にthrough: :categories_articlesというkeyをつけます。
これもcategory.categories_articlesで、カテゴリーに属する記事へアクセス可能になります。
Modelの設定は以上になります。
viewでの呼び出し方
記事に紐づくカテゴリーを呼び出すには、 Article.modelに設定したキーarticles_categoriesを利用し 呼び出します。
ArticlesController def show @article = Article.find(params[:id]) end
show. slim
- @article.categories_articles.each do |categories_article| = categories_article.category.name
1記事に対して複数のカテゴリーを設定しているので、 viewで値を表示する際は繰り返し処理で呼び出しを行わないとエラーになります
こちらはslimで記載していますが、erbでも対応可能です。 slimの詳細は【初心者・独学者向け】Ruby on Railsのviewを劇的に変える?!Slim入門をご覧ください
※値を取得できなかった場合の処理も記載する必要がありますが、こちらは割愛しております。
新規記事投稿時にカテゴリーを紐付ける
newアクションで@article.categories_articles.buildとすると articleに紐づく中間テーブルのインスタンスが精製される
その後create アクションのストロングパラメーターで category_idsを受け取って登録処理が行われます。
ArticlesController def new @article = Article.new @article.categories_articles.build end def create @article = Article.new(article_params) if @article.save redirect_to dashboards_path else render 'new' end end def article_params params.require(:article).permit(:title, :content, { :category_ids=> [] }) end
下記フォームでは1記事に対して複数のカテゴリーを設定できるようにしています。
その為、collectioncheckboxesで複数選択できるようにしています。
また引数の項目はcategory_idsと複数形にし、controllerのストロングパラメーターで受け取ります。
new.html = simple_form_for @article do |f| = f.input :title = f.collection_check_boxes :category_ids, Category.all, :id, :name
以上になります
その他の関連記事
Ruby on Railsのscopeメソッドで検索を効率化する
27歳から未経験で自社サービス会社のエンジニアに転職された方の勉強法や通学したプログラミングスクール
27歳から未経験で自社サービス会社のエンジニアに転職された方の転職媒体やエンジニア情報の収集先など
【初心者・独学者向け】Ruby on RailsでテーブルやModelを削除する際のコマンド
Ruby on Rails5で簡易ブログを作成する1 | VIew Controller ルートを作成する
Ruby on RailsでRedisを利用してランキング機能を実装する
Ruby on Railsとtwitterの投稿機能を連携する
職歴を作るためにSESに就職して、Web系エンジニアへ転職は可能か
Rubyでサイトをスクレイピングし、ローカルに画像を保存する
MySQLでテーブルへカラムを追加するALTER TABLE ~ ADD