3.3 アソシエーション

1対1の関連を定義する

モデルで「1対1」の関係を定義するにはhas_onebelongs_toを定義します。 例えば「Userが一つのPostを持っている」という状態を定義するには、 Userhas_one、そしてPostbelongs_toを定義し、外部キーuser_idPostに追加する必要があります。

図で表すと以下のようになります。

3-4-1.png

class User < ApplicationRecord
  has_one :post
end

class Post < ApplicationRecord
  belongs_to :user
end

上記のように定義することで、UserからPostを参照、またPostにもbelongs_toが定義されているので、Userを参照することが可能になります。

1対多の関連を定義する

モデルで「1対多」の関係を定義するにはhas_manybelongs_toを定義します。 例えば「Userが複数のPostを持っている」という状態を定義するには、 Userhas_many、そしてPostbelongs_toを定義し、外部キーuser_idPostに追加する必要があります。

図で表すと以下のようになります。

3-4-1.png

class User < ApplicationRecord
  has_many :posts # 複数形になる
end

class Post < ApplicationRecord
  belongs_to :user
end

上記のように定義することで、Userから複数のPostを参照、またPostにもbelongs_toが定義されているので、Userを参照することが可能になります。

多対多の関連を定義する

モデルで「多対多」の関係を定義するには複数関連させるための中間モデルを定義します。 例えば「Categoryが複数のPostを持っている、またPostは複数のCategoryの属している」という状態を定義するには、中間モデルCategoryPostが必要になります。

図で表すと以下のようになります。

3-4-3.png

CategoryPostCategoryPostそれぞれに属しており、CategoryPostはそれぞれ中間モデルを通して、もう一方のモデルを参照することになります。

class Category < ApplicationRecord
  has_many :category_posts
  has_many :posts, through: :category_posts
end

class CategoryPost < ApplicationRecord
  belongs_to :category
  belongs_to :post
end

class Post < ApplicationRecord
  has_many :category_posts
  has_many :categories, through: :category_posts
end

そして、CategoryおよびPostはそれぞれhas_manyで中間モデルを、またhas_many参照先のモデルをthroughオプションをつけて定義します。

ポリモーフィックな関連を定義する

ポリモーフィック関連は、1つのモデルが他の複数のモデルに属していることを表現することができます。 例えばImageモデルがあり、このモデルをUserモデルとPostモデルの両方に関連させることができます。

図で表すと以下のようになります。

3-4-4.png

ポリモーフィックモデルを定義するときは、参照先のidと参照先のモデル名を格納する2つのカラムが必要になります。

class User < ApplicationRecord
  has_many :images, as: :imageable
end

class Post < ApplicationRecord
  has_many :images, as: :imageable
end

class Image < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

これによりUserおよびPostモデルからは複数のImageを参照できるようになります。

1対1のモデルの操作

1対1関連のモデルを定義します。

class User < ApplicationRecord
  has_one :post
end

class Post < ApplicationRecord
  belongs_to :user
end

このとき以下のメソッドが利用できます。associationは関連モデルになる。例)user.post

メソッド
association 自分を参照しているオブジェクトを取得
association=(associate) associateを参照元として設定する
build_association(attributes = {}) 新しいオブジェクトを作成
create_association(attributes = {}) 新しいオブジェクトを作成して保存
create_association!(attributes = {}) 新しいオブジェクトを作成して保存、失敗時に例外が発生

関連のモデルを作成する

$ post = user.create_post(title: 'これはタイトルです', body: 'これは本文です。')
=> #<Post id: 4, title: "これはタイトルです", body: "これは本文です。", created_at: "2018-06-26 16:05:42", updated_at: "2018-06-26 16:05:42", published_at: nil, user_id: 1>

関連のモデルを取得する

$ post.user
=> #<User id: 1, email: nil, password: nil, created_at: "2018-06-26 15:52:29", updated_at: "2018-06-26 15:52:29">

関連のモデルを更新する

$ user.post.update(title: 'タイトルを更新しました!')
=> true

$ user.post
=> #<Post id: 4, title: "タイトルを更新しました!", body: "これは本文です。", created_at: "2018-06-26 16:05:42", updated_at: "2018-06-27 08:22:55", published_at: nil, user_id: 1>

関連のモデルを削除する

$ user.post.destroy
=> #<Post id: 4, title: "タイトルを更新しました!", body: "これは本文です。", created_at: "2018-06-26 16:05:42", updated_at: "2018-06-27 08:22:55", published_at: nil, user_id: 1>

$ user.post
=> nil

1対多のモデルの操作

1対多関連のモデルを定義します。

class User < ApplicationRecord
  has_many :posts
end

class Post < ApplicationRecord
  belongs_to :user
end

このとき以下のメソッドが利用できます。collectionは関連モデルになる。例)user.posts

メソッド
collection 関連づけされているモデルのコレクションを取得
collection<<(object, …) collectionにobjectを追加
collection.delete(object, …) objectを削除
collection.destroy(object, …) objectおよびその関連を削除
collection.build(attributes = {}, …) 新しいオブジェクトを作成
collection.create(attributes = {}) 新しいオブジェクトを作成して保存

関連のモデルを作成する

$ post = user.posts.create(title: 'これはタイトルです', body: 'これは本文です。')
=> #<Post id: 5, title: "これはタイトルです", body: "これは本文です。", created_at: "2018-06-27 08:36:22", updated_at: "2018-06-27 08:36:22", published_at: nil, user_id: 1>

関連のモデルを取得する

$ user.posts
=> #<ActiveRecord::Associations::CollectionProxy [#<Post id: 5, title: "これはタイトルです", body: "これは本文です。", created_at: "2018-06-27 08:36:22", updated_at: "2018-06-27 08:36:22", published_at: nil, user_id: 1>]>

関連のモデルをすべて削除する

$ user.posts.destroy_all
=> #[<Post id: 5, title: "これはタイトルです", body: "これは本文です。", created_at: "2018-06-27 08:37:45", updated_at: "2018-06-27 08:37:45", published_at: nil, user_id: 1>]

$ user.posts
=>  #<ActiveRecord::Associations::CollectionProxy []>

多対多のモデルの操作

多対多関連のモデルを定義します。

class Category < ApplicationRecord
  has_many :category_posts
  has_many :posts, through: :category_posts
end

class CategoryPost < ApplicationRecord
  belongs_to :category
  belongs_to :post
end

class Post < ApplicationRecord
  has_many :category_posts
  has_many :categories, through: :category_posts
end

このとき以下のメソッドが利用できます。collectionは関連モデルになる。例)category.posts

メソッド
collection 関連づけされているモデルのコレクションを取得
collection<<(object, …) collectionにobjectを追加
collection.delete(object, …) objectを削除
collection.destroy(object, …) objectおよびその関連を削除
collection.build(attributes = {}, …) 新しいオブジェクトを作成
collection.create(attributes = {}) 新しいオブジェクトを作成して保存

関連のモデルを作成する

$ post = category.posts.create(title: "カテゴリの投稿")
=> #<Post id: 5, title: "カテゴリの投稿", body: nil, created_at: "2018-06-27 08:53:18", updated_at: "2018-06-27 08:53:18", published_at: nil, user_id: nil>

関連のモデルを取得する

$ category.posts
=> #<ActiveRecord::Associations::CollectionProxy [#<Post id: 5, title: "カテゴリの投稿", body: nil, created_at: "2018-06-27 08:53:18", updated_at: "2018-06-27 08:53:18", published_at: nil, user_id: nil>]>

関連のモデルをすべて削除する

$ category.posts.destroy_all
=> [#<Post id: 5, title: "カテゴリの投稿", body: nil, created_at: "2018-06-27 08:53:18", updated_at: "2018-06-27 08:53:18", published_at: nil, user_id: nil>]

$ category.posts
=>  #<ActiveRecord::Associations::CollectionProxy []>

results matching ""

    No results matching ""