开发者

Ruby on Rails has_many through self-referential following/follower relationships

There are a number of posts and threads on has_many :through, but I haven't found any that cover specifically what I'm trying to do.

I have a User model and a Friendships model. A user has many users that are following them, as well as many followers. It is the usual Twitter model.

For a given user, I want to setup Active Record relationships that return the actual users that are following the user and that the user is a follower of.

These are the relationships that I have setup:

class User < ActiveRecord::Base

  has_many :following, :class_name => 'User', :through => :friendships, :foreign_key => 'user_id'

  has_many :followers, :class_name => 'User', :through => :friendships, :foreign_key => 'friend_id'

end

class Friendship < ActiveRecord::Base

  belongs_to :user
  belongs_to :following, :class_name => 'User', :foreign_key => 'friend_id'
  belongs_to :follower, :class_name => 'User', :foreign_key => 'user_id'

end

The Following relationship works - it generates the below join:

SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.friend_id WHERE ((`friendships`.user_id = 1))

All is grand.

However, the Follower relationship does not work. I've tried a number of variations, but most seem to return the same set of results as Following.

I need the join to be setup as follows to return the correct result set.

SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.user_id WHERE ((`friendships`.friend_id = 1)); 

Where am I going wrong?

I can set this up using the finder_sql option on the has_many, but it seems like there should be a better way.

has_many :followers, :class_name => 'User', :finder_sql => 'SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.user_id WHERE ((`friendships`.friend_id = #{ id }))'

Thanks!


I made a bit of progress and finally got the relationship working by breaking the relationships into two parts, as was shown in this response: Self-referential has_many :through with customized :primary key issue

# FOLLOWING
has_many :friendships_to, :foreign_key => 'user_id', :class_name => 'Friendship'
has_many :following, :through => :friendships_to, :class_name => 'User'

# FOLLOWERS
has_many :friendships_from, :foreign_key => 'friend_id', :class_name => 'Friendship'
has_many :followers, :through => :friendships_from, :class_name => 'Use开发者_StackOverflow社区r'

However, while it was possible to have a one-line version of the relationship for following

has_many :following, :class_name => 'User', :through => :friendships, :foreign_key => 'user_id'

I still wasn't able to get it to work for followers. Still wondering how this could be done?


You need to make sure ActiveRecord knows what the source association for the User#friends and likewise the followers and specify the class and foreign_key for the relationships that ActiveRecord can't extrapolate from the association names.

class Following < ActiveRecord::Base

  belongs_to :user
  belongs_to :followed, :class_name => 'User'

end

class User < ActiveRecord::Base

  has_many :followings
  has_many :friends, :through => :followings, :source => 'followed'

  has_many :followeds, :class_name => 'Following', :foreign_key => 'followed_id'
  has_many :followers, :through => :followeds, :source => :user

end


I'm kind of a noob in a learning process, but this models seem cleaner to me:

class User < ActiveRecord::Base
  has_many :followings
  has_many :followers, through: :followings
end

class Following < ActiveRecord::Base
  belongs_to :user
  belongs_to :follower, class_name: 'User'
end
  • Source Treehouse : https://www.youtube.com/watch?v=jSUWu50XK48
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜