我有一个User模型,我希望通过使用has_and_belongs_to_many的自联接来连接自己。我几乎按预期工作了,除了我希望它以两种方式关联两个用户。
我的用户类:
class User < ActiveRecord::Base
...
has_and_belongs_to_many :friends,
autosave: true,
class_name: 'User',
join_table: :friendships,
foreign_key: :user_id,
association_foreign_key: :friend_user_id
...
end
我的迁移:
class CreateFriendships < ActiveRecord::Migration
def self.up
create_table :friendships, id: false do |t|
t.integer :user_id
t.integer :friend_user_id
end
add_index(:friendships, [:user_id, :friend_user_id], :unique => true)
add_index(:friendships, [:friend_user_id, :user_id], :unique => true)
end
def self.down
remove_index(:friendships, [:friend_user_id, :user_id])
remove_index(:friendships, [:user_id, :friend_user_id])
drop_table :friendships
end
end
我的问题:
user1 = User.find(1)
user2 = User.find(2)
user1.friends << user2
user1.reload.friends.exists?(user2) # true
user2.reload.friends.exists?(user1) # false <- My problem
如何让这种关系双向发挥作用?由于友谊在这种情况下始终是相互的,因此关于SO的其他问题使得它看起来应该是可能的,我希望最后两个陈述都能返回真实。
答案 0 :(得分:2)
不那么强硬的方法是在你自己的方法中建立友谊:
class User < ActiveRecord::Base
def make_friend(user)
# TODO: put in check that association does not exist
self.friends << user
user.friends << self
end
end
并称之为
user1.make_friend(user2)
# should set both friends know about each other
使用ActiveRecord::Associations
方法覆盖时,更难以欺骗。例如。 has_and_belongs_to_many's
方法collection<<(object, …)
可以针对您的案例进行修改:
class User < ActiveRecord::Base
attr_accessor :reversed # we use it to avoid stack level too deep issue
has_and_belongs_to_many :friends, ... do
def << (new_friend)
reversed = true
# it should not trigger on our friend record as self.reversed is true
new_friend.friends << self unless new_friend.reversed
super new_friend
end
end
end
注意:我不确定self
方法中的<<
含义,因此您可能应该通过关系对象以某种方式挖掘真实对象实例。
答案 1 :(得分:0)
你也可以......
user2.friends << user1
这意味着有两个连接记录。