1 対 多の関係モデルの作成
コマンド
rails g model comment board:references name:string comment:text
comment
=> 1 対 多 に該当する作成するモデル名
board:references
=> 1 対 多に該当するモデル名
(:references
と記述することでboardモデルに紐付けるboard_idがcommentモデルに作成される。
)
name:string comment:text
=> 新しく作成するカラム名とデータ型
作成されたmigrateファイル
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.references :board, null: false, foreign_key: true
t.string :name, null: false
t.text :comment,null: false
t.timestamps
end
end
end
foreign_key: true
は外部キー制約を意味する。
boardsテーブルに存在しないidに対し新規でcommentテーブルのboard_idカラムを作成できない。
即ち、boardテーブルに紐付けられないものは作成できなくするためのもの。
その他
null: false
は入力必須にするためのもの。
テーブルの作成
rails db:migrate
board modelへアソシエーションを記述
class Board < ApplicationRecord
has_many: comments
validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end
has_many: comments
Boardsテーブルからcommentsテーブルを見たときに, 1 対 多の関係になるため,
Boardモデルに記述するアソシエーションはhas_many: comments
となる。
comment modelへアソシエーションを記述
class Comment < ApplicationRecord
belongs_to :board
end
belongs_to :board
はモデル作成時に自動で記述される。
belongs_to :board
はcommentモデルから見たboardモデル。
多 対 多のアソシエーション
中間テーブルboard_tag_relations
を用意して多 対 多のアソシエーションを実現する。
元テーブル | 中間テーブル | 元テーブル | |
---|---|---|---|
テーブル名 | Boards | board_tag_relations | Tags |
カラム | id | id | id |
name | board_id | name | |
title | tag_id | ||
body |
Step1:Tagモデルを作成する
コマンド
rails g model tag name:string
Step2:board_tag_relationsモデル(中間テーブル)を作成する
コマンド
rails g model board_tag_relations board:references tag:references
関連付けれる両方の元テーブルに対してreferences(参照)をつけて関連付けをする。
Step3:モデルの関連付けの追記
作成されたモデルを修正する。
中間テーブルはすでに関連付けをされているのでこのまま。
class BoardTagRelation < ApplicationRecord
belongs_to :board
belongs_to :tag
end
tagモデル
tagモデルから見た中間テーブルは多の関係になるので,has_many
で関連付け。
また関連先のboardsテーブルも指定し,through:(スルー)ここポイント を指定した後に中間テーブルを指定する。
class Tag < ApplicationRecord
has_many :board_tag_relations
has_many :boards, through: :board_tag_relations
end
boardモデル
boardモデルから見た、中間テーブルは多の関係になるので,has_many
で関連付け。
また関連先のtagsテーブルも指定し,through:(スルー)ここポイント を指定した後に中間テーブルを指定する。
class Board < ApplicationRecord
has_many :comments
has_many :board_tag_relations
has_many :tags, through: :board_tag_relations
validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end
dependentオプション
dependentオプションとは、モデルに関連されたデータが削除されたときに、その関連に紐付かれたデータも同時に削除する機能
コード
Boardモデル
class Board < ApplicationRecord
# 多 対 多の関係のアソシエーション
has_many :comments, dependent: :delete_all #dependent: :delete_allで削除している
has_many :board_tag_relations, dependent: :delete_all #dependent: :delete_allで削除している
has_many :tags, through: :board_tag_relations
validates :name, presence: true, length: { maximum: 10 }
validates :title, presence: true, length: { maximum: 30 }
validates :body, presence: true, length: { maximum: 1000 }
end
tagモデル
class Tag < ApplicationRecord
has_many :board_tag_relations :dependent: :delete_all #dependent: :delete_allで削除している
has_many :boards, through: :board_tag_relations
end
注意点
dependent
オプションを使用するときは、controllerのdestroyアクションに使用するメソッドはdelete
メッソッドは使用できないため、替わりにdestroy
メソッドを使用する。
def destroy
@board.destroy #dependentオプションをモデルに設定している場合はdeleteメソッドではなく、destroyメソッドを使用する。
redirect_to boards_path, flash: { notice: "「#{@board.title}」の掲示板を削除しました。"}
end