Lets say I have the following table of Users
id, type
1, "A"
2, "B"
3, "B"
4, "A"
5, "B"
6, "A"
There are two user types. "A" users, and "B" users. "A"s can be connected to many "B"s, and "B"s can be connected to many "A"s. Let's say we have the following 'connections' table
id, A_id, B_id
1, 1, 2
2, 4, 2
3, 4, 3
4, 6, 5
5, 1, 5
6, 4, 5
Which would represent the following graph:
I could have an "A"s table that stores the foreign_key indexes of the users with the "A" type (i.e. 'these users are type "A"), and similarly for "B", in which case I could just define a simple has_many association through the connections table from "A" to "B" and vice versa.
I want to be able to type something like a.b to produce all the "B" that the 'a' is connected to, as well as b.a to produce all the "A" that the 'b' is connected to.
My question is: can this many-to-many association between "A" and "B" be defined using a single User model instead? Can a self-join be used?
Thank you for your time
Looks like a pretty standard example of has_many :through
and STI
.
Given:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :type
t.timestamps
end
end
end
class CreateConnections < ActiveRecord::Migration
def change
create_table :connections do |t|
t.integer :a_user_id
t.integer :b_user_id
t.timestamps
end
end
end
class User < ActiveRecord::Base
end
class AUser < User
has_many :connections
has_many :b_users, :through => :connections
end
class BUser < User
has_many :connections
has_many :a_users, :through => :connections
end
class Connection < ActiveRecord::Base
belongs_to :a_user
belongs_to :b_user
end
When (rails console output snipped for brevity):
>> a_user = AUser.create!
>> b_user = BUser.create!
>> connection = a_user.connections.build
>> connection.b_user = b_user
>> connection.save!
Then:
>> a_user.b_users
=> ActiveRecord::Associations::CollectionProxy of BUsers
If your AUser
and BUser
objects will have different sets of attributes then you should use Polymorphic Associations instead, which requires creating a couple more tables but really doesn't complicate things much.