⚠️ This article was posted over 2 years ago. The information might be outdated. ⚠️
Table of Contents
- Associations
- 本記事で扱う Associations
- One to One
- CreateUsers
- CreateProfiles
- app/models/user.rb
- app/models/profile.rb
- One to Many
- CreateUsers
- CreatePosts
- app/models/user.rb
- app/models/profile.rb
- Many to Many(has_many_through)
- CreatePosts(モデルA)
- CreateTags(モデルB)
- CreateTaggings(モデルC)
- app/models/post.rb
- app/models/tag.rb
- app/models/tagging.rb
- Many to Many(has_and_belongs_to_many)
- CreateUsers(モデルA)
- CreateRoles(モデルB)
- CreateRolesUsers
- app/models/user.rb
- app/models/tag.rb
- Polymorphic
- CreateUsers(モデルA)
- CreatePosts(モデルB)
- Createpictures(モデルC)
- Createpictures(モデルC)
- app/models/user.rb
- app/models/post.rb
- app/models/picture.rb
- References
Associations
本記事で扱う Associations
- One to One
- One to Many
- Many to Many(has_many_through)
- Many to Many (has_and_belongs_to_many)
- Plymorphic One to Many
One to One
One to One
はモデル同士に「1対1」関係がある事を示す。
モデル A の1つのレコードがモデル B の1つのインスタンスを丸ごと所有している。
例えば、1人のユーザーが1つのプロファイルを持つ場合。
各テーブルのカラム
# CreateUsers
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.timestamps
end
end
end
# CreateProfiles
class CreateProfiles < ActiveRecord::Migration[5.1]
def change
create_table :profiles do |t|
t.string :name
t.references :user
t.timestamps
end
end
end
各モデル
# app/models/user.rb
class User < ApplicationRecord
has_one :profile
end
# app/models/profile.rb
class Profile < ApplicationRecord
belongs_to :user
end
One to One で頻繁に使用されるメソッド
user.profile :該当ユーザーのプロファイル情報を取得
user.build_profile :該当ユーザーのプロファイルを作成(DBに保存しない)
user.create_profile :該当ユーザーのプロファイルを作成(DBに保存する)
One to Many
One-to-Many
は他のモデルとの間に「1対多」の関係がある事を示す。
モデル A の1つのレコードが0個以上のモデル B のインスタンスを所有している。
例えば、1人のユーザー(user
)が複数の投稿(post
)を持つ場合。
各テーブルのカラム
# CreateUsers
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.timestamps
end
end
end
# CreatePosts
class CreatePosts < ActiveRecord::Migration[5.1]
def change
create_table :posts do |t|
t.string :title
t.references :user
t.timestamps
end
end
end
各モデル
# app/models/user.rb
class User < ApplicationRecord
has_many :posts
end
# app/models/profile.rb
class Post < ApplicationRecord
belongs_to :user
end
One to Many で頻繁に使用されるメソッド
user.posts :該当ユーザーの全ての投稿を取得。
user.posts << post :新しい関係を作成する。
user.posts.build({}) :該当ユーザーの投稿を作成する。(DBに保存しない)
user.posts.create({}) :該当ユーザーの投稿を作成する。(DBに保存する)
post.build_user :ユーザー作成。(DBに保存しない)
post.create_user :ユーザー作成。(DBに保存する)
Many to Many(has_many_through)
Many-to-Many
は他のモデルとの間に「多対多」の関係がある事を示す。
モデル A とモデル B 共に相互の複数のインスタンスを所有している。
has_many_through
の方式ではモデル C(結合モデル)がモデル A とモデル B を
繋ぐ。
例えば、複数の投稿(post
)が複数のタグ(tag
)を持つ場合。
各テーブルのカラム
# CreatePosts(モデルA)
class CreatePosts < ActiveRecord::Migration[5.1]
def change
create_table :posts do |t|
t.string :title
t.timestamps
end
end
end
# CreateTags(モデルB)
class CreateTags < ActiveRecord::Migration[5.1]
def change
create_table :tags do |t|
t.string :name
t.timestamps
end
end
end
# CreateTaggings(モデルC)
class CreateTaggings < ActiveRecord::Migration[5.1]
def change
create_table :taggings do |t|
t.references :tag
t.references :post
t.timestamps
end
end
end
各モデル
# app/models/post.rb
class Post < ApplicationRecord
has_many :taggins
has_many :tags, through: :taggings
end
# app/models/tag.rb
class Tag < ApplicationRecord
has_many :taggins
has_many :posts, through: :taggings
end
# app/models/tagging.rb
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :post
end
Many to Many(has_many_through)で頻繁に使用されるメソッド
post.tags :該当投稿の全てのタグを取得。
post.tags << tag :新しい関係を作成する。
post.tags << [tag1, tag2] :新しい関係を作成する。
post.tag_ids :該当投稿のタグのIDを全て取得する。
post.tags.destroy(tag) :該当投稿からtagを消去する。
post.taggings :該当投稿の全てのtaggingsを取得。
post.taggings.build(tag_id: tag.id) :投稿とtagの関係を作成する。(DBに保存しない)
post.taggings.create(tag_id: tag.id) :投稿とtagの関係を作成する。(DBに保存する)
post.tags.build({}) :該当投稿と結合モデル(tagging)で結びつくタグを作成する。(DBに保存しない)
post.tags.create({}) :該当投稿と結合モデル(tagging)で結びつくタグを作成する。(DBに保存する)
tag.posts.build({}) :該当タグと結合モデル(tagging)で結びつく投稿を作成する。(DBに保存しない)
tag.posts.create({}) :該当タグと結合モデル(tagging)で結びつく投稿を作成する。(DBに保存する)
Many to Many(has_and_belongs_to_many)
Many-to-Many
は他のモデルとの間に「多対多」の関係がある事を示す。
モデル A とモデル B 共に相互の複数のインスタンスを所有している。
has_and_belongs_to_many
の方式では1つの JOIN テーブルを介してモデル A とモデル B が互いのインスタンスを多数所有し合う。。
例えば、複数の投稿(post
)が複数のタグ(tag
)を持つ場合。
各テーブルのカラム
# CreateUsers(モデルA)
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.timestamps
end
end
end
# CreateRoles(モデルB)
class CreateRoles < ActiveRecord::Migration[5.1]
def change
create_table :roles do |t|
t.string :name
t.timestamps
end
end
end
# CreateRolesUsers
class CreateRolesUsers < ActiveRecord::Migration[5.1]
def change
create_table :roles_users, id: false do |t|
t.references :user, foreign_key: true
t.references :role, foreign_key: true
end
end
end
各モデル
# app/models/user.rb
class User < ApplicationRecord
has_and_belongs_to_many :roles
end
# app/models/tag.rb
class Role < ApplicationRecord
has_and_belongs_to_many :users
end
Many-to-Many(has_and_belongs_to_many)で頻繁に使用されるメソッド
Many-to-Many(has_many_through)
で頻繁に使用されるメソッドを参照。
Polymorphic
Polymorphic
であるモデル A が他の複数のモデル(B,C,D)に属していることを、1 つの関連付けだけで表現することが可能。
例えば、コメント(picture
)が投稿(post
)がとユーザー(user
)に所属している場合。
各テーブルのカラム
# CreateUsers(モデルA)
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.timestamps
end
end
end
# CreatePosts(モデルB)
class CreatePosts < ActiveRecord::Migration[5.1]
def change
create_table :posts do |t|
t.string :title
t.references :user
t.timestamps
end
end
end
# Createpictures(モデルC)
class Createpictures < ActiveRecord::Migration[5.1]
def change
create_table :pictures do |t|
t.string :body
t.integer :imageable_id
t.string :imageable_type
t.timestamps
end
add_index :pictures, [:imageable_type, :imageable_id]
end
end
以下のようにreferencesを使用してより簡潔に書くことも可能。
# Createpictures(モデルC)
class Createpictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.text :body
t.references :imageable, polymorphic: true, index: true
t.timestamps
end
end
end
各モデル
# app/models/user.rb
class User < ApplicationRecord
has_many :posts
has_many :pictures, as: :imageable
end
# app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :pictures, as: :imageable
end
# app/models/picture.rb
class picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
Polymorphic で頻繁に使用されるメソッド
post.pictures :該当投稿の全てコメントを取得。
user.pictures :該当ユーザーの全てコメントを取得。
post.pictures.build :該当投稿に結びつくコメントを作成。(DBに保存しない)
post.pictures.create :該当投稿に結びつくコメントを作成。(DBに保存する)
user.pictures.build :該当ユーザーに結びつくコメントを作成。(DBに保存しない)
user.pictures.create :該当ユーザーに結びつくコメントを作成。(DBに保存する)
post.pictures << picture.new({}) :該当ポストにコメントを関連づけ。
user.pictures << picture.new({}) :該当ユーザーにコメントを関連づけ。
以下のような Image ができるイメージ。
[
{id: 1, name: "ss", imageable_id: 1, imageable_type: "Post"},
{id: 2, name: "ss", imageable_id: 1, imageable_type: "User"}
]