ページ

2013/07/30

MVCモデルにおけるModelの関係性とRailsでのアソシエーションの設定

Rails を勉強中です。学んだことをちょっとずつまとめていきたいと思います。
誤りがあれば教えていただけると幸いです。

アソシエーションって何?

日本語訳すると、「つながり」とか「関係性」とか訳される。
MVCフレームワークを使うと出てくるアソシエーションは、モデル同士の関係性のこと。
すごく大雑把に言えば、テーブルの JOIN の繋ぎ方のこと。たぶん合ってる。

なぜアソシエーションが必要なのか?

設定しておくと Rails では JOIN を明示的に書かなくても SELECT できたり、
紐付いたデータを一緒に削除できたり、色々とフレームワークの支援を得られる。
何故アソシエーションなの?(Why Associations?) - Active Record Associations - 株式会社ウサギィwiki
Active Record Associations — Ruby on Rails Guides

MVC モデルにおける Model の関係性

  1. 1対1関連(has_one, belongs_to)
  2. 経由モデルありの1対1関連(has_one :through)
  3. 1対多関連(has_many, belongs_to)
  4. 中間テーブルに属性ありの多対多関連(has_many :through)
  5. 中間テーブルに属性なしの多対多関連(has_and_belongs_to_many)
  6. ポリモーフィック関連(has_many :as)
Rails での主なアソシエーションの種類は上記の6つ。
ちゃんと理解するために身近なサンプルを作ってみることにした。

1対1関連(has_one, belongs_to)

User - Blog
上記のような 1 User に 1 Blog というブログサービスを想定したアソシエーションの設定は以下のようになる。
class User < ActiveRecord::Base
    has_one :blog
end
class Blog < ActiveRecord::Base
    belongs_to :user
end
has_one アソシエーション - Active Record Associations - 株式会社ウサギィwiki
belongs_to アソシエーション - Active Record Associations - 株式会社ウサギィwiki
The belongs_to Association - Active Record Associations — Ruby on Rails Guides
The has_one Association - Active Record Associations — Ruby on Rails Guides

経由モデルありの1対1関連(has_one :through)

User - Blog - Setting
User から Blog を通して Setting にアクセスするような3つのモデルの直線的な関係性は以下のように設定する。
class User < ActiveRecord::Base
    has_one :blog
    has_one :setting, through: :blog
end
class Blog < ActiveRecord::Base
    belongs_to :user
    has_one :setting
end
class Setting < ActiveRecord::Base
    belongs_to :blog
end
has_one :through アソシエーション - Active Record Associations - 株式会社ウサギィwiki
The has_one :through Association - Active Record Associations — Ruby on Rails Guides

1対多関連(has_many, belongs_to)

Category - Article
1 カテゴリに複数の記事、1 記事に 1 カテゴリという関係性を定義したい場合は以下のように設定する。
class Category < ActiveRecord::Base
    has_many :article
end
class Article < ActiveRecord::Base
    belongs_to :category
end
has_many アソシエーション - Active Record Associations - 株式会社ウサギィwiki
The has_many Association - Active Record Associations — Ruby on Rails Guides

中間テーブルに属性ありの多対多関連(has_many :through)

Blog - Reader - User
中間テーブルが属性(理論的な意味でのカラムのこと)を持つ際の多対多の関連性は以下のように定義する。
class Blog < ActiveRecord::Base
    has_many :readers
    has_many :users, through: :readers
end
class Reader < ActiveRecord::Base
  belongs_to :user
  belongs_to :blog
end
class User < ActiveRecord::Base
    has_many :readers
    has_many :blogs, through: :readers
end
has_many :through アソシエーション - Active Record Associations - 株式会社ウサギィwiki
The has_many :through Association - Active Record Associations — Ruby on Rails Guides

中間テーブルに属性なしの多対多関連(has_and_belongs_to_many)(HABTM)

Article - Tag
中間テーブルが属性を持たず、2つのテーブルの関係性の情報しか持たない場合は以下のように定義する。
class Article < ActiveRecord::Base
    has_and_belongs_to_many :tags
end
class Tag < ActiveRecord::Base
    has_and_belongs_to_many :articles
end
has_and_belongs_to_many アソシエーションの規約
  • 中間テーブルを作成しなければならない。
  • 中間テーブルのテーブル名は参照先のテーブル名を辞書順に「_」で連結しなければならない。(※)
  • 中間テーブルの主キー列を無効化しなくてはならない。
  • 中間テーブルの外部キー列は「参照先のモデル名_id」の形式にしなければならない。
  • 中間テーブルのタイムスタンプ列を削除しなくてはならない。
※ 両方のモデルの has_and_belongs_to_many アソシエーションの指定の後に
join_table でテーブル名を指定すれば任意のテーブル名を指定することができる。
rails g migration CreateArticlesTags でマイグレーションファイルが生成されるので
上記の規約に従い、以下のように修正する。
class CreateArticlesTags < ActiveRecord::Migration
  def change
    create_table :articles_tags, :id => false do |t|
      t.references :article, index: true
      t.integer :article_id
      t.references :tag, index: true
      t.integer :tag_id
    end
  end
end
has_and_belongs_to_many アソシエーション - Active Record Associations - 株式会社ウサギィwiki
The has_and_belongs_to_many Association - Active Record Associations — Ruby on Rails Guides
[Rails]中間テーブルを使って他テーブルの情報を参照する - has_and_belongs_to_many (m:n) のケース
has_and_belongs_to_many アソシエーションのための結合テーブルの作成 - 株式会社ウサギィwiki
Creating Join Tables for has_and_belongs_to_many Associations — Ruby on Rails Guides

ポリモーフィック関連(has_many :as)

Blog - Article
 └ Picture ┘
あるモデルが1つ以上の他のモデルに属する場合、以下のように定義する。
class Blog < ActiveRecord::Base
    has_many :pictures, as: :imageable
end
class Article < ActiveRecord::Base
    has_many :pictures, as: :imageable
end
class Picture < ActiveRecord::Base
    belongs_to :imageable, polymorphic: true
end
polymorphic アソシエーション - Active Record Associations - 株式会社ウサギィwiki
Polymorphic Associations - Active Record Associations — Ruby on Rails Guides

参考

ruby/rails/RailsGuidesをゆっくり和訳してみたよ/Active Record Associations - 株式会社ウサギィwiki
Active Record Associations — Ruby on Rails Guides