#has_many
テーブル同士を関連づけるためのものです。
関連づけているのでテーブルの操作等が効率的にできます。
##関連付け
関連付けとはテーブル等で関係があるものについて明示的に表現することです。
上記のような関係があったときPetテーブル
に「犬」と「猫」があってその飼い主が``Ownerテーブル`「佐藤さん」だったときに、
佐藤さんが犬と猫を手放した場合、佐藤さんが飼っているペットを全て削除するということができます。
こちらは関係が「1」対「多」
になります。
このようなテーブルの関係の場合、Petテーブル
にkeeper_id(飼い主)
とseller(販売員)
が加わっておりPetテーブル
に2つの以上の関連付けがされています。
こうするとPetを登録したときに飼い主と販売員の2人を関連づけることができます。
関連づけることでテーブルを追加したり削除するときにまとめることができます。
上の関係は「多」対「多」
になります。
##has_manyの基本的な実装方法
rails g model owner name:string
rails g model castle castle:string owner_id:integer
「所有者」と「城」のモデルを作成します。
rails db:migrate
で作成されたマイグレーションファイルを実行します。
Castle.create(castle:"大阪城",owner_id:2)
Castle.create(castle:"岐阜城",owner_id:3)
Castle.create(castle:"安土城",owner_id:3)
Castle.create(castle:"江戸城",owner_id:1)
Castle.create(castle:"首里城",owner_id:4)
Owner.create(name:"徳川家康")
Owner.create(name:"豊臣秀吉")
Owner.create(name:"織田信長")
Castleテーブル
とOwnerテーブル
に上記のカラムを追加します。
has_many :castles, dependent: :destroy
このようにユーザモデルに記載しOwnerがCastlesを所有していることにします。
dependent: :destroy
と記載することでオーナーが所有する城を全て削除することを簡潔に命令できるようになる。
#belongs_to
belongs_to :owner
こうすることでオーナー
は城
を所有しているという関係になります。
##関連名を変更できる
belongs_to :holder ,class_name: 'Owner',foreign_key: 'owner_id'
このような記載方法にすることでbelongs_to :〇〇〇
の〇〇〇部分が変更可能になります。
ただし追記でclass_name
は指定のテーブルを、foreign_key
にはモデル+_id
を記載しなければいけません。
これでholderという名前でOwnerテーブルにアクセスすることができるようになります。
##referencesを使用してidを関連づける方法
rails g model castle castle:string owner_id:integer
↓
rails g model castle castle:string owner:references
このようにモデルを作成する際に関連づけられたidを設定していましたが、記載の方法は上記のように変更することができます。
owner:references
これでowner_idがinteger型で作成されます。
またapp/model/castle.rbにはbelongs_to :owner
が自動的に追加されます。
##throughを用いてより複雑な関連付けを行う
has_many :through
を使用すると「多」対「多」
を表現することが可能です。
rails g model keeper name:string
rails g model seller name:string
rails g model pet name:string keeper:references seller:references
rake db:migrate
モデル「keeper」、「seller」、「pet」を追加しマイグレーション実行。
#app/models/keeper.rb
has_many :pets
has_many :sellers, through: :pets
#app/models/seller.rb
has_many :pets
has_many :keepers, through: :pets
モデルごとのファイルに上記を記載することで「多」対「多」
の関係が成り立ちます。
また、 petモデルを作成するときにrefalenceを使用していることにより、自動的にbelongs_toが追加されます。
##「1」対「多」、「多」対「多」でのデータ追加
owner = Owner.find(2) #豊臣秀吉を取得
owner.castles.create(castle:"伏見城”)
Hirb.enable #表形式で出力
Castle.all
#【実行結果】
+----+--------+----------+---------------------------+---------------------------+
| id | castle | owner_id | created_at | updated_at |
+----+--------+----------+---------------------------+---------------------------+
| 1 | 大阪城 | 2 | 2017-07-05 17:41:28 +0900 | 2017-07-05 17:41:28 +0900 |
| 2 | 安土城 | 3 | 2017-07-05 17:41:28 +0900 | 2017-07-05 17:41:28 +0900 |
| 3 | 江戸城 | 1 | 2017-07-05 17:41:28 +0900 | 2017-07-05 17:41:28 +0900 |
| 4 | 伏見城 | 2 | 2017-07-06 10:13:22 +0900 | 2017-07-06 10:13:22 +0900 |
+----+--------+----------+---------------------------+---------------------------+
4 rows in set
こちらは「1」対「多」
になります。
owner_idが「2」で伏見城が追加されています。
keeper = Keeper.create(name:"田中太郎") #新しい飼い主
seller = Seller.create(name:"立川絢香" ) #販売した人
keeper.pets.create(name:"ウーパールーパー",seller: seller) #ウーパールーパーを購入
Hirb.enable #表形式で出力
Pet.all
【実行結果】
+----+------------------+-----------+-----------+---------------------------+---------------------------+
| id | name | keeper_id | seller_id | created_at | updated_at |
+----+------------------+-----------+-----------+---------------------------+---------------------------+
| 1 | プラナリア | 1 | 3 | 2017-07-06 10:47:40 +0900 | 2017-07-06 10:47:40 +0900 |
| 2 | 文鳥 | 3 | 2 | 2017-07-06 10:47:40 +0900 | 2017-07-06 10:47:40 +0900 |
| 3 | カブトムシ | 3 | 1 | 2017-07-06 10:47:40 +0900 | 2017-07-06 10:47:40 +0900 |
| 4 | 猫 | 2 | 2 | 2017-07-06 10:47:40 +0900 | 2017-07-06 10:47:40 +0900 |
| 5 | 犬 | 2 | 1 | 2017-07-06 10:47:40 +0900 | 2017-07-06 10:47:40 +0900 |
| 6 | クモ | 1 | 2 | 2017-07-06 10:47:41 +0900 | 2017-07-06 10:47:41 +0900 |
| 7 | ウーパールーパー | 4 | 4 | 2017-07-06 10:53:40 +0900 | 2017-07-06 10:53:40 +0900 |
+----+------------------+-----------+-----------+---------------------------+---------------------------+
7 rows in set
こちらが「多」対「多」
になります。