2

I am trying to set up a many to many relationship between User and User, where users have many followers and also follow many.

I created a pivot table via a model called Follow, this is the migration file:

class CreateFollows < ActiveRecord::Migration
  def change
    create_table :follows do |t|
      t.integer :follower_id, index: true
      t.integer :followed_id, index: true

      t.timestamps null: false
    end
  add_index :follows, [ :follower_id, :followed_id ], unique: true
  end
end

However, I can't get to define the has_many. I tried doing this:

user.rb:

has_many :followers, foreign_key: "followed_id", class_name: "Follow"
has_many :followed, foreign_key: "follower_id", class_name: "Follow"

follow.rb:

class Follow < ActiveRecord::Base
    belongs_to :followed, class_name: "User"
    belongs_to :follower, class_name: "User"
end

However when trying to add a user to the followers or followed collection like this @user.followers << @user_to_be_followed I am getting an type error that saying Follow is expected, not User. Makes sense.

But how can I define has_many saying that the model should be User but the foreign keys are called as defined and the table is follows?

How can I achieve this?

Edit searching around I stumbled on this an looks like the way I did it is correct...

Community
  • 1
  • 1
dabadaba
  • 9,064
  • 21
  • 85
  • 155
  • Have you considered using [acts_as_follower](https://github.com/tcocca/acts_as_follower) – Antarr Byrd Jul 29 '15 at 21:09
  • I didn't know about that one. But know that I made the effort I would like to do it the way I am trying. Especially when it looks like I did it right – dabadaba Jul 29 '15 at 21:11

1 Answers1

0

Note that I have changed Follow to Subscription. Follow is a verb not a noun which makes it really awkward as a model name.

When using has_many though you both have to set up a relation to the join model and a has_many through: :join_relation to get a direct relationship to the other model. This case is kind of special since User has a double relationship to Subscription.

class Subscription < ActiveRecord::Base
  belongs_to :follower, class_name: 'User'
  belongs_to :followed, class_name: 'User'
end

class User < ActiveRecord::Base
  # This looks kind of weird but we have to tell Rails how to find the
  # correct foreign_key for both of the relation types
  has_many :subscriptions,
    foreign_key: :follower_id

  has_many :subscriptions_as_followed,
    class_name: 'Subscription',
    foreign_key: :followed_id

  has_many :followed,
    class_name: 'User',
    through: :subscriptions,
    source: :followed

  has_many :followers,
    class_name: 'User',
    through: :subscriptions_as_followed,
    source: :follower

  # Subscribes to another user
  def follow!(other_user)
    subscriptions.find_or_create_by(followed: other_user)
  end
end
max
  • 96,212
  • 14
  • 104
  • 165
  • The [other question you linked to](http://stackoverflow.com/questions/3397920/relationship-like-twitter-followers-followed-in-activerecord) only sets up a relation to the join model. You would have to do `user.following.first.user` which is ridulous. We can do better than that. – max Jul 29 '15 at 22:46