Railsドキュメント

アソシエーション(関連付け)

参照元テーブルから参照先テーブルを参照

説明

参照元テーブルから参照先テーブルを参照するための設定

使い方

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

ソースコード