アソシエーション(関連付け)
参照元テーブルから参照先テーブルを参照
説明
参照元テーブルから参照先テーブルを参照するための設定
使い方
belongs_to(関連モデル名, scope=nil, オプション={})
オプション
オプション | 説明 | デフォルト値 |
---|---|---|
:class_name | 関連を設定するモデル名を指定 | |
:foreign_key | 参照先を参照するための外部キーの名前を指定 | :foreign_key |
:foreign_type | 参照先を参照するための外部キーの型を指定 | :foreign_type |
:primary_key | 主キーを指定 | id |
:dependent | :destroyで参照先が削除される場合に参照元もDBから削除 | |
:counter_cache | カウンタキャッシュを使用するか | |
:polymorphic | ポリモーフィック関連を定義 | |
:validate | 関連オブジェクトのバリデーションの有無 | false |
:autosave | 親の保存でロードされたオブジェクトも保存するか | |
:touch | updated_atまたはupdated_onが保存または破棄された場合に現在の時刻を設定するか | |
:inverse_of | モデルを指定 | |
:optional | 関連付けの確認は行わないか? | |
:required | 関連付けの確認するか? | true |
:default | 特定のカラムの初期化 | |
:strict_loading | 厳格な読み込みを実施 | |
:ensuring_owner_was | 呼び出されるインスタンスメソッドを指定 |
追加されているメソッド
メソッド | 説明 |
---|---|
association | 関連するオブジェクトを生成 |
association=(associate) | 引数を参照元オブジェクトとして設定。それ以外の参照元との関連は破棄 |
build_association(attributes = {}) | 新しいオブジェクトを生成。引数にはオブジェクトを生成するのに必要なパラメータを指定。この時点では保存されない |
create_association(attributes = {}) | 新しいオブジェクトを生成して保存。引数にはオブジェクトを生成するのに必要なパラメータを指定 |
create_association!(attributes = {}) | 新しいオブジェクトを生成して保存。引数にはオブジェクトを生成するのに必要なパラメータを指定。失敗時に例外を発生 |
reload_association | キャッシュではなくデータベースから直接値を取得 |
association_changed? | 新しいオブジェクトが割り当てられ、次の保存で外部キーが更新される場合はtrue |
association_previously_changed? | 前回の保存で新しいオブジェクトを参照するように更新された場合true |
保存
参照元オブジェクトが未保存の場合
- saveのタイミングで外部キーが設定され保存
- 参照先オブジェクトが未保存であれば、saveのタイミングで自動的に保存
参照元オブジェクトが保存済みの場合
- 保存済みの場合には、生成したタイミングで自動的にDBに保存
例
UserとProjectの関係
基本形(オプションなし)
belongs_to :user
クラス名としてUserを指定
belongs_to :admin_user, class_name: "User"
user_id = 2を抽出
belongs_to :user, conditions: "user_id = 2"
逆順で並び替える
belongs_to :user, order: "id DESC"
データを削除するときに関連するテーブルを削除
belongs_to :user, dependent: :destroy
外部キーを指定
belongs_to :user, foreign_key: "blog_id"
特定のキーの初期化
belongs_to :account, default: -> { company.account }
ソースコード
* [GitHub](https://github.com/rails/rails/blob/984c3ef2775781d47efa9f541ce570daa2434a80/activerecord/lib/active_record/associations.rb#L769)
1対1の関連を宣言
説明
別のモデルとの1対1の関連付けを指定
使い方
has_one(関連モデル名, scope=nil, オプション引数)
オプション
オプション | 説明 |
---|---|
:class_name | 関連名と参照元のクラス名を異なるものにしたい場合に指定 |
:dependent | 値を:destroyにすると、参照先が削除される場合に参照元もDBから削除 |
:foreign_key | 関連で使用する外部キー名 |
:foreign_type | オブジェクトタイプを指定 |
:primary_key | 参照先のテーブルに定義されている外部キーの名前を指定 |
:as | ポリモーフィック関連を定義 |
:through | 結合モデルの指定 |
:source | has_one :throughの元となるオブジェクトを指定 |
:source_type | polymorphicの指定 |
:validate | オブジェクトが保存されると、バリデイトが実行される |
:autosave | 親のオブジェクトが保存されると、ロードされたオブジェクトも保存 |
:inverse_of | モデルを指定 |
:required | 関連先オブジェクトが存在するかバリデーション |
:strict_loading | 関連するレコードが読み込まれるたびに厳格な読み込みを実施 |
:ensuring_owner_was | 呼び出されるインスタンスメソッドを指定 |
追加されるメソッド
メソッド | 説明 |
---|---|
association(force_reload = false) | 自分自身を参照しているオブジェクトを返す。オブジェクトが無い場合は、nilを返す |
association=(associate) | 引数を参照元オブジェクトとして設定。それ以外の参照元との関連は破棄 |
build_association(attributes = {}) | 新しいオブジェクトを作成。引数にはオブジェクトを生成するのに必要なパラメータを指定。この時点では保存されない |
create_association(attributes = {}) | 新しいオブジェクトを作成して保存。引数にはオブジェクトを生成するのに必要なパラメータを指定 |
create_association!(attributes = {}) | 新しいオブジェクトを作成して保存。引数にはオブジェクトを生成するのに必要なパラメータを指定。エラー時に例外を発生 |
reload_association | リロード |
保存
参照先オブジェクトが未保存の場合
- saveのタイミングで外部キーが設定され保存
- 参照先オブジェクトが未保存であれば、saveのタイミングで自動的に保存
参照先オブジェクトが保存済みの場合
- 保存済みの場合には、作成するタイミングで自動的にDBに保存
例
UserとProjectの関係
マイグレーションファイル
class CreateUsersProjectsTable < ActiveRecord::Migration
def self.up
create_table :users_projects, id: false do |t|
t.integer :user_id
t.integer :project_id
end
end
def self.down
drop_table :users_projects
vend
end
Userモデル
class User < ActiveRecord::Base
has_one :project
end
Projectモデル
class Project < ActiveRecord::Base
belongs_to :user
end
クラス名としてUserを指定
has_one :admin_user, class_name: "User"
user_id = 2を抽出
has_one :user, conditions: "user_id = 2"
逆順で並び替える
has_one :user, order: "id DESC"
データを削除するときに関連するテーブルを削除
has_one :user, dependent: :destroy
外部キーを指定
has_one :user, foreign_key: "blog_id"
ソースコード
1対多の関連を宣言
説明
1対多や多対多の関連付けを指定
使い方
has_many(関連モデル名, scope=nil, オプション引数)
オプション
オプション | 説明 |
---|---|
:class_name | 関連名と参照元のクラス名を異なるものにしたい場合に指定 |
:foreign_key | 参照元のテーブルに定義されている外部キーの名前を指定 |
:foreign_type | オブジェクトタイプを指定 |
:primary_key | 参照先のテーブルに定義されている外部キーの名前を指定 |
:dependent | 値を:destroyにすると、参照先が削除される場合に参照元もDBから削除 |
:counter_cache | カウンターキャッシュ |
:as | ポリモーフィック関連を定義 |
:through | 結合モデルの指定 |
:source | has_one :through の元となるオブジェクトを指定 |
:source_type | polymorphicの指定 |
:validate | オブジェクトが保存されると、バリデイトが実行される |
:autosave | 親のオブジェクトが保存されると、ロードされたオブジェクトも保存 |
:inverse_of | モデル名を指定 |
:extend | 関連を拡張 |
:strict_loading | 関連レコードが読み込まれるたびに厳密な読み込みを実施 |
:ensuring_owner_was | 呼び出されるインスタンスメソッドを指定 |
追加されるメソッド
メソッド | 説明 |
collection(force_reload = false) | 関連付けられている配列 |
collection«(object, …) | collectionにobjectを追加 |
collection.delete(object, …) | 1つ以上のobjectを削除 |
collection.destroy(object, …) | 1つ以上のobjectを削除 |
collection=objects | 多対多でひも付いたモデルを更新 |
collection_singular_ids | 関連付けられているオブジェクトのIDの配列 |
collection_singular_ids=ids | 主キーを切り替える |
collection.clear | すべて切断 |
collection.empty? | オブジェクトが関連付けられていなければtrue |
collection.size | サイズ |
collection.find(…) | 通常のfindメソッド |
collection.exists?(…) | 与えられた条件に一致するモデルが存在するか確認 |
collection.build(attributes = {}, …) | 新しいモデルを作り、多対多で関連付けるがDBは更新しない |
collection.create(attributes = {}) | 新しいモデルを作り、多対多で関連付けてDBを更新 |
collection.reload | リロード |
保存
参照先オブジェクト、参照元オブジェクトのどちらかが未保存の場合
- saveのタイミングで両方とも保存
参照先オブジェクト、参照元オブジェクトの保存済みの場合
- 参照元オブジェクトの外部キーが更新され、保存
例
UserとProjectの関係
マイグレーションファイル
class CreateUsersProjectsTable < ActiveRecord::Migration
def self.up
create_table :users_projects, id: false do |t|
t.integer :user_id
t.integer :project_id
end
end
def self.down
drop_table :users_projects
end
end
Userモデル
class User < ActiveRecord::Base
has_many :projects
accepts_nested_attributes_for :projects
end
Projectモデル
class Project < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
クラス名としてUserを指定
has_many :admin_user, class_name: "User"
accepts_nested_attributes_for :admin_user
user_id = 2を抽出
has_many :user, conditions: "user_id = 2"
accepts_nested_attributes_for :user
逆順で並び替える
has_many :user, order: "id DESC"
accepts_nested_attributes_for :user
Group
has_many :users, group: "category"
accepts_nested_attributes_for :users
外部キーを指定
has_many :user, foreign_key: "blog_id"
accepts_nested_attributes_for :user
ソースコード
多対多の関連を宣言
説明
多対多の関連付けを指定
使い方
has_and_belongs_to_many(関連モデル名, scope=nil, オプション引数)
オプション
オプション | 説明 |
---|---|
:class_name | 関連モデルのクラス名を指定。関連モデル名から推測できない場合のみ指定 |
:join_table | 結合テーブルの名前を指定 |
:foreign_key | 多対多の関連で使用する外部キーの名前を指定 |
:association_foreign_key | 多対多の関係で関連先への外部キーを指定 |
:validate | 現在のモデルを保存する場合、関連先のバリデーションを実行 |
:autosave | 親モデルに合わせて、保存や削除 |
:strict_loading | 関連するレコードが読み込まれるたびに厳格な読み込みを実施 |
使えるようになるメソッド
メソッド | 説明 |
---|---|
collection(force_reload = false) | 多対多でひも付いた先のモデルである一覧を取得 |
collection«(object, …) | 1つ以上のモデルを多対多の関連に追加 |
collection.delete(object, …) | 1つ以上のモデルを多対多の関連から外す |
collection.destroy(object, …) | 1つ以上のモデルを多対多の関連から外す |
collection=objects | 多対多でひも付いたモデルを更新 |
collection_singular_ids | 多対多でひも付いたモデルのidの配列を取得 |
collection_singular_ids=ids | 多対多でひも付いたモデルのidが指定された物に更新 |
collection.clear | 多対多の関連をすべて削除 |
collection.empty? | 多対多の関連にあるモデルが1つもないときにtrue |
collection.size | 多対多でひも付いたモデル数を取得 |
collection.find(id) | 多対多の関連モデルでfindを実行 |
collection.exists?(…) | 与えられた条件に一致するモデルが存在するか確認 |
collection.build(attributes = {}) | 新しいモデルを作り、多対多で関連付けるがDBは更新しない |
collection.create(attributes = {}) | 新しいモデルを作り、多対多で関連付けてDBを更新 |
collection.reload | リロード |
例
UserとProjectの関係
マイグレーションファイル
class CreateUsersProjectsTable < ActiveRecord::Migration
def self.up
create_table :users_projects, id: false do |t|
t.integer :user_id
t.integer :project_id
end
end
def self.down
drop_table :users_projects
end
end
Userモデル
class User < ActiveRecord::Base
has_and_belongs_to_many :projects
end
Projectモデル
class Project < ActiveRecord::Base
has_and_belongs_to_many :users
end
ソースコード
ポリモーフィック関連
説明
- belongs_to宣言に:polymorphicオプションを指定すると、ポリモーフィック関連になる
- 参照先となるモデルをあらかじめ定義せず、参照元となるオブジェクトごとに指定する関連
使い方
- 参照元となるモデルに対応するテーブルに、参照先のIDと参照先クラスを指定するカラムをそれぞれ生成
- 参照先のIDを保存するカラムは「belongs_to宣言で渡す関連名_id」
- 参照先クラスを指定するカラムは「関連名type」
例
ポリモーフィック関連を利用するマイグレーションファイルの生成
$ rails generate model AttachmentImage attachable_id:integer attachable_type:string
class CreateAttachmentImage < ActiveRecord::Migration
def self.up
create_table :attachment_images do |t|
t.integer :attachable_id
t.string :attachable_type
t.timestamps
end
end
ボリモーフイツク関連を利用する宣言
class AttachmentImage < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
end
class Blog < ActiveRecord::Base
has_many :entries
has_one :attachment_image, as: :attachable
end
class Entry < ActiveRecord::Base
belongs_to :blog
end
def self.down
drop_table :attachment_images
end
カウンターキャッシュ
説明
子モデルの数を親モデルのカラムに保存
概要
- デフォルトを0
- カラム名は、子モデルのテーブル名_countがおすすめ
使い方
belongs_to(:親モデル, counter_cache: 親モデルのカラム)
例
def self.up
add_column :entries, :comments_count, :integer, default: 0
end
belongs_to :entry, counter_cache: :comments_count
モデルのコレクションを生成(newの別名)
説明
モデルのコレクションを生成
newの別名
使い方
モデルのコレクション.build(属性={}, ブロック引数)
例
モデルを生成
person.pets.build
属性を指定
person.pets.build(name: 'Fancy-Fancy')
ブロックを指定
person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}])
ソースコード
モデルのコレクションを生成して保存
説明
モデルのコレクションを生成して保存
使い方
モデルのコレクション.create(属性={}, ブロック引数)
例
生成して保存
person.pets.create(name: 'Fancy-Fancy')
#=> <Pet id: 1, name: "Fancy-Fancy", person_id: 1>
複数作成
person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}])
#=> [
# <Pet id: 2, name: "Spook", person_id: 1>,
# <Pet id: 3, name: "Choo-Choo", person_id: 1>
# ]
ソースコード
モデルのコレクションからIDを指定してレコードを取得
説明
モデルのコレクションからIDを指定してレコードを取得
使い方
モデルのコレクション.find(ID..)
例
IDを指定してレコードを取得
person.pets.find(1)
#=> <Pet id: 1, name: "Fancy-Fancy", person_id: 1>
複数指定
person.pets.find(2, 3)
#=> [
# <Pet id: 2, name: "Spook", person_id: 1>,
# <Pet id: 3, name: "Choo-Choo", person_id: 1>
# ]
ソースコード
モデルのコレクションからカラムを指定して取得
説明
モデルのコレクションからカラムを指定して取得
使い方
モデルのコレクション.select(カラム.., ブロック引数)
例
カラムを指定して取得
person.pets.select(:name)
複数カラム指定
person.pets.select(:id, :name)
ブロック指定
person.pets.select { |pet| /oo/.match?(pet.name) }
ソースコード
モデルのコレクションから先頭のレコードを取得
説明
モデルのコレクションから先頭のレコードを取得
使い方
モデルのコレクション.first(取得する件数=nil)
例
先頭のレコードを取得
person.pets.first
#=> <Pet id: 1, name: "Fancy-Fancy", person_id: 1>
複数件取得
person.pets.first(2)
#=> [
# <Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
# <Pet id: 2, name: "Spook", person_id: 1>
# ]
ソースコード
モデルのコレクションから最後のレコードを取得
説明
モデルのコレクションから最後のレコードを取得
使い方
モデルのコレクション.last(取得する件数=nil)
例
最後のレコードを取得
person.pets.last
#=> <Pet id: 3, name: "Choo-Choo", person_id: 1>
複数件取得
person.pets.last(2)
#=> [
# <Pet id: 2, name: "Spook", person_id: 1>,
# <Pet id: 3, name: "Choo-Choo", person_id: 1>
# ]
ソースコード
モデルのコレクションの指定した数のレコードを取得
説明
モデルのコレクションの指定した数のレコードを取得
使い方
モデルのコレクション.take(取得する件数=nil)
例
モデルのコレクションの指定した数のレコードを取得
person.pets.take
複数件取得
person.pets.take(2)
ソースコード
モデルのコレクションを生成して保存
説明
モデルのコレクションを生成して保存
使い方
モデルのコレクション.delete(レコード..)
例
生成して保存
person.pets.delete(Pet.find(1))
複数指定
person.pets.delete(Pet.find(1), Pet.find(3))
ソースコード
モデルのコレクションからすべてのレコードを削除
説明
モデルのコレクションからすべてのレコードを削除
dependentオプションが指定されている場合はそれに従う
使い方
モデルのコレクション.delete_all(依存=nil)
例
person.pets.delete_all
ソースコード
指定されたレコードを破棄しコレクションから削除
説明
指定されたレコードを破棄しコレクションから削除
dependentオプションを無視してデータベースからレコードが削除される
使い方
モデルのコレクション.destroy(レコード..)
例
コレクションから削除
person.pets.destroy(Pet.find(1))
複数指定
person.pets.destroy(Pet.find(2), Pet.find(3))
ソースコード
データベースから直接コレクションのレコードを削除
説明
データベースから直接コレクションのレコードを削除
dependentオプションを無視してデータベースからレコードが削除される
使い方
モデルのコレクション.destroy_all()
例
person.pets.destroy_all
ソースコード
全てのレコード数を取得
説明
全てのレコード数を取得
使い方
モデルのコレクション.count(カラム名=nil, ブロック引数)
例
person.pets.count
#=> 3
ソースコード
モデルのコレクションが空か
説明
空か
使い方
モデルのコレクション.empty?()
例
class Person < ActiveRecord::Base
has_many :pets
end
person.pets.count #=> 1
person.pets.empty? #=> false
person.pets.delete_all
person.pets.count #=> 0
person.pets.empty? #=> true
ソースコード
モデルのコレクションの長さを取得
説明
モデルのコレクションの長さ
使い方
モデルのコレクション.length()
例
class Person < ActiveRecord::Base
has_many :pets
end
person.pets.length #=> 3
# executes something like SELECT "pets".* FROM "pets" WHERE "pets"."person_id" = 1
ソースコード
モデルのコレクションのサイズを取得
説明
モデルのコレクションのサイズを取得
使い方
モデルのコレクション.size()
例
person.pets.size
#=> 3
ソースコード
アソシエーションが読み込まれたか
説明
アソシエーションが読み込まれたか
使い方
モデル.loaded?()
例
person.pets.loaded? #=> false
person.pets.records
person.pets.loaded? #=> true
ソースコード
空でないか
説明
空かチェック
使い方
モデルのコレクション.any?()
例
空かチェック
class Person < ActiveRecord::Base
has_many :pets
end
person.pets.count # 0
person.pets.any? # false
person.pets << Pet.new(name: 'Snoop')
person.pets.count # 0
person.pets.any? # true
ブロック
person.pets
# [<Pet name: "Snoop", group: "dogs">]
person.pets.any? do |pet|
pet.group == 'cats'
end
# false
person.pets.any? do |pet|
pet.group == 'dogs'
end
# true
ソースコード
複数のレコードがあるか
説明
モデルのコレクションに複数のレコードがあるか
2以上のレコードがある場合にtrue
使い方
モデルのコレクション.many?()
例
class Person < ActiveRecord::Base
has_many :pets
end
person.pets.count #=> 1
person.pets.many? #=> false
person.pets << Pet.new(name: 'Snoopy')
person.pets.count #=> 2
person.pets.many? #=> true
ソースコード
レコードをユニークにするか
説明
レコードをユニークにするか
使い方
モデルのコレクション.distinct(ユニークにするか=true)
例
ユニークにする
person.pets.select(:name).distinct
ユニークにしない
person.pets.select(:name).distinct.distinct(false)
ソースコード
モデルのコレクションに指定したレコードが存在するか
説明
モデルのコレクションに指定したレコードが存在するか
使い方
モデルのコレクション.include?(レコード)
例
person.pets.include?(Pet.find(20))
#=> true
ソースコード
モデルのコレクションからデータベースからリロード
説明
モデルのコレクションからデータベースからリロード
使い方
モデルのコレクション.reload()
例
person.pets.reload
ソースコード
モデルのコレクションを他の配列で置き換える
説明
モデルのコレクションを他の配列で置き換える
使い方
モデルのコレクション.replace(他の配列)
例
person.pets
#=> [<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]
other_pets = [Pet.new(name: 'Puff', group: 'celebrities')]
person.pets.replace(other_pets)
person.pets
#=> [<Pet id: 2, name: "Puff", group: "celebrities", person_id: 1>]
ソースコード
アソシエーションをアンロード
説明
アソシエーションをアンロード
使い方
モデルのコレクション.reset()
例
person.pets.reset