Rails 4.0 で多対多関連

この記事内では、"timeline"モデルと,"user"モデルをどのようにして接続する事が出来るかを見ていきます。

timeline.user
user.timeline

等でアクセス出来るように作っています(つもりです)。

Rubyや、Railsの経験が浅いため、もっと良い方法を知っている方、間違えを見つけた方はコメントを頂けるととてもうれしいです。

またポリモーフィズムを使用した関連付けに関しては触れていません。

あくまで導入部分だと思って参照して頂ければとおもいます。

HABTM

has_and_belongs_to_many を使った例。

モデルをいくつかの種類に分けて参照させたいときなどに便利です。

#/app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :timelines_member, :class_name => 'Timeline',
                          :foreign_key => :member_timeline_id, :association_foreign_key => :member_id,
                          :join_table => :timelines_members

  has_and_belongs_to_many :timelines_observer, :class_name => 'Timeline',
                          :foreign_key => :observer_timeine_id, :association_foreign_key => :observer_id,
                          :join_table => :timelines_observers
end
#/app/models/timeline.rb
class Timeline < ActiveRecord::Base
  has_and_belongs_to_many :members, :class_name => 'User',
                          :foreign_key => :member_id, :association_foreign_key => :member_timeline_id,
                          :join_table => :timelines_members

  has_and_belongs_to_many :observers, :class_name => 'User', 
                          :foreign_key => :observer_id, :association_foreign_key => :observer_timeine_id,
                          :join_table => :timelines_observers
end
#/db/migrate/[TIMESTAMP]_timelines_members.rb
class TimelinesMembers < ActiveRecord::Migration
  def change
    create_table :timelines_members, id: false do |t|
      t.integer :member_id, null: false
      t.integer :member_timeline_id, null: false
    end
    add_index(:timelines_members, [:member_id, :member_timeline_id], :unique => true)
  end
end
#/db/migrate/[TIMESTAMP]_timelines_obserbers.rb
class TimelinesObservers < ActiveRecord::Migration
  def change
    create_table :timelines_observers, id: false do |t|
      t.integer :observer_id, null: false
      t.integer :observer_timeline_id, null: false
    end
    add_index(:timelines_observers, [:observer_id, :observer_timeline_id], :unique => true)
  end
end

HM with relationship table

has_manyとbelongs_toで関連を作るのですが、2つのモデルの間にrelationshipテーブルを挟む方法です。

2つのモデルの間に”状態”等のステータスを持たせたい場合に有効です。

#/app/models/user.rb
  has_many :timeline_user_relationships
  has_many :timelines, :through => :timeline_user_relationships
end
#/app/models/timeline.rb
class Timeline < ActiveRecord::Base
  has_many :timeline_user_relationships
  has_many :users, :through => :timeline_user_relationships
end
#/app/models/timeline_user_relationship.rb
class TimelineUserRelationship < ActiveRecord::Base
  belongs_to :user
  belongs_to :timeline
end
#/db/migrate/[TIMESTAMP]_create_timeline_user_relationships.rb
class CreateTimelineUserRelationships < ActiveRecord::Migration
  def change
    create_table :timeline_user_relationships do |t|
      t.references :user, index: true
      t.references :timeline, index: true
      t.integer :role

      t.timestamps
    end
    add_index(:timeline_user_relationships, [:user_id, :timeline_id], :unique => true)
  end
end

create_join_table

Rails 4.0から追加されたものです。
Railsドキュメントにも記載されています。
http://railsdoc.com/migration#テーブルを結合して作成(create_join_table)

手軽に作成出来るので、とりあえず関連をつけたいという時に使うと良いかと思います。

#/app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :timelines
end
#/app/models/timeline.rb
class Timeline < ActiveRecord::Base
  has_and_belongs_to_many :users
end
#/db/migrate/[TIMESTAMP]_create_timelines_users.rb
class CreateUsersGroups < ActiveRecord::Migration
  def change
    create_join_table :timelines, :users
    add_index(:groups_users, [:group_id, :user_id], :unique => true)
  end
end


ざっと3種類紹介しましたが、option等は必要になった際に使ってみて追加していこうと思います。