How To Setup Twitter Style Following In Your User Model

Setting up a Twitter-like following scheme can be a little tricky at first glance. The reason being that your User model will need to refer to itself in order for a user to follow another user. Here’s how to look at the relationships:

user-follows

We can build this relationship using self-referential associations, and a model as a join table. We’ll call the joining model Follow.

db/migrate/create_follows.rb
class CreateFollows < ActiveRecord::Migration
  def self.up
    create_table :follows do |t|
      t.integer :follower_id
      t.integer :followed_id
      ...

Next, we can add the follower and followed associations to the our new Follow model.

app/models/follow.rb
class Follow < ActiveRecord::Base
  belongs_to :follower, :class_name => "User"
  belongs_to :followed, :class_name => "User"
end

Lastly, we can set up the self-referential associations in the User model.

app/models/user.rb
class User < ActiveRecord::Base
  has_many :follows, :foreign_key => "follower_id", :class_name => "Follow", :dependent => :destroy
  has_many :users_followed, :through => :follows, :source => :followed
 
  has_many :followings, :foreign_key => "followed_id", :class_name => "Follow", :dependent => :destroy
  has_many :users_following, :through => :followings, :source => :follower
end

This allows the User to be both followed and a follower. See this blog post for a good explanation of self-referential associations.

Your controller can look basically like this:

app/controllers/follows_controller.rb
class FollowsController < ApplicationController
 
  def create
    @follow = current_user.follows.build(:followed_id => params[:followed_id])
    if @follow.save
      flash[:notice] = "You are now following #{@follow.followed.name}"
      redirect_to user_path(@follow.followed)
    else
      flash[:error] = "Unable to follow."
      redirect_to user_path(@follow.followed)
    end
  end
 
  def destroy
    @follow = current_user.follows.find_by_followed_id(params[:followed_id])
    @follow.destroy
    flash[:notice] = "Removed follow."
    redirect_to user_path(params[:followed_id])
  end
 
end