38
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on Railsにおける多対多の関係の実装

Last updated at Posted at 2018-11-15

現在プログラマとしての転職・起業を視野にRuby/Railsを勉強しています。

今回はRailsでの多対多の関係を実装する際の記録として記事にしました。

モデル

今回はサロンとそのサロンの属するカテゴリを実装する、という形です。

サロンの情報をもつSalonモデルとカテゴリの情報を持つCategoryモデル、その2つを繋ぐ中間テーブルとしてClassificationモデルを作成します。

1つのSalonは複数のCategoryを持ちえ、1つのCategoryは複数のSalonを持つ関係とします。

*deviseでSalonの登録ができるようにしている前提で、current_salonを使っています。

多対多を実装した経緯

今回のように1つの商品が複数のカテゴリーを持ち、1つのカテゴリーが複数の商品をもつ実装は1対多(has_many)の形でも実装できますが、『Webエンジニアのためのデータベース技術[実践]入門』も参考に、より綺麗な形での実装のためにhas_many throghを用いた多対多で実装。

モデルの作成

```ruby:model $rails g model Salon name:string $rails g model Category name:string ``` モデルを作成後、中間テーブルとなるモデルを作成します。
model
$rails g model Classification salon:references category:references

user:referencesというような形にすることでそれぞれのモデルと紐付けさせます。
こうすることでUserProjectモデルは自動的に以下のようにそれぞれのモデルとの紐付けがなされた状態で作成されます。

models/classification.rb
class Classification < ApplicationRecord
  belongs_to :salon
  belongs_to :category
end

マイグレーションは以下のように自動的に外部キーが設定された形で作成されています。

db/migrate/create_classifications.rb
class CreateClassifications < ActiveRecord::Migration[5.2]
  def change
    create_table :classifications do |t|
      t.references :salon, foreign_key: true
      t.references :category, foreign_key: true

      t.timestamps
    end
  end
end

Classificationモデルにはbelongs_toが自動で設定されていますが、ProductモデルとCategoryモデルには手動で追加する必要があります。
多対多の形での実装では、中間テーブルとのhas_many関係の記述と、その中間テーブルを通したCategoryモデルとの紐付けの2つのhas_many throughを記述する必要があります。

models/salon.rb
class Salon < ApplicationRecord
  has_many :classifications
  has_many :categories, through: :classifications
end
models/category.rb
class Category < ApplicationRecord
  has_many :classifications
  has_many :salons, through: :classifications
end

モデルの実装は以上。

Controllerの実装

中間テーブルにもデータを保存するためのコードを書いていきます。 今回はSalon作成後、そのSalonが属するカテゴリを登録する形で実装します。
controllers/categories_controller.rb
class CategorysController < ApplicationController
  def create
    @salon = current_salon
    @category = @salon.categoies.build(category_params)
    if @salon.save
      flash[:success] = "カテゴリーを登録しました"
      redirect_to root_url
    else
      flash[:danger] = "カテゴリーが登録できませんでした"
      redirect_to root_url
    end
  end

  private
  def category_params
    params.require(:category).permit(:name)
  end
end

Controllerの実装は以上です。

Viewsの実装

カテゴリーは今回は好きなカテゴリーを追加できるような形での実装にし、form_forではtext_fieldを使って登録するようにしました。 また、ログインした後はトップページにユーザーページを表示させ、そこにform_forを設置しています。
views/layouts/home.html.erb
<%= form_for(current_salon.categories.build) do |f| %>
  <%= f.label :"カテゴリー登録" %>
  <%= f.text_field :name, placeholder: "Category Name" %>
  <%= f.submit "Registrate" %>
<% end %>

特定のSalonのカテゴリー名を全て表示させるような場合には以下のように記述します。

views/layouts/home.html.erb
<% @salon.categoies.each do |category| %>
  <%= category.name %>
<% end %>

とりあえずはこのくらいで。

38
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?