app/models/concerns/follower.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Follower
  extend ActiveSupport::Concern

  included do
    has_many :followings, :foreign_key => :follower_id, :dependent => :destroy

    def following(opts={}, order='updated_at DESC')
      followings.order(order).where(opts).includes(:followable).map(&:followable)
    end

    def follow(obj)
      follow = Following.where(followable: obj, follower: self).first_or_create
      follow.save
    end

    def unfollow(obj)
      following = Following.find_by(followable: obj, follower: self)
      following.destroy if following
    end

    def follow?(obj)
      followings.where(followable: obj).exists?
    end

    def following_activities
      activities = PublicActivity::Activity.arel_table
      followings = Following.arel_table
      sql = activities.join(followings).on(
        # we want activities related to objetcs followed by this user
        # AND activities owned by users followed by this user
        followings[:followable_type].in([activities[:trackable_type], activities[:owner_type]])
      ).where(
          # Activities from objects followed by this user
          Arel::Nodes::Grouping.new(
            activities[:trackable_id].eq(followings[:followable_id]).and(
              activities[:trackable_type].eq(followings[:followable_type])
            )
          ).or(
          # Activities owned by users followed by this user
          Arel::Nodes::Grouping.new(
            activities[:owner_id].eq(followings[:followable_id]).and(
              followings[:followable_type].eq(self.class.name)
            )
          )
        ).and(
          # Only followed by this user
          followings[:follower_id].eq(self.id)
        ).and(
          # But remove activities owned by this user itself
          activities[:owner_type].eq(self.class.name).and(
            activities[:owner_id].not_eq(self.id))
        )
      ).project('activities.id')
      # Convert to ActiveRecord Relation
      PublicActivity::Activity.includes(:trackable).where(
        activities[:id].in(sql)).order("activities.created_at desc")
    end
  end
end