lib/follow_system/follow.rb
###
# FollowSystem module
#
# This module defines common behavior in follow system
###
module FollowSystem
###
# Follow class
#
# This class defines the follow model in follow system
###
class Follow < ActiveRecord::Base
###
# Belongs to followee association configuration
###
belongs_to :followee, polymorphic: :true
###
# Belongs to follower association configuration
###
belongs_to :follower, polymorphic: :true
###
# Creates a {Follow} relationship between a {Follower} object and a {Followee} object
#
# @param [Follower] follower - the {Follower} of the relationship
# @param [Followee] followee - the {Followee} of the relationship
# @return [Boolean]
###
def self.follow(follower, followee)
validate_followee(followee)
validate_follower(follower)
if follows?(follower, followee)
false
else
follow = scope_by_follower(follower).scope_by_followee(followee).build
follow.save
true
end
end
###
# Destroys a {Follow} relationship between a {Follower} object and a {Followee} object
#
# @param [Follower] follower - the {Follower} of the relationship
# @param [Followee] followee - the {Followee} of the relationship
# @return [Boolean]
###
def self.unfollow(follower, followee)
validate_followee(followee)
validate_follower(follower)
if follows?(follower, followee)
follow = scope_by_follower(follower).scope_by_followee(followee).take
follow.destroy
true
else
false
end
end
###
# Toggles a {Follow} relationship between a {Follower} object and a {Followee} object
#
# @param [Follower] follower - the {Follower} of the relationship
# @param [Followee] followee - the {Followee} of the relationship
# @return [Boolean]
###
def self.toggle_follow(follower, followee)
validate_followee(followee)
validate_follower(follower)
if follows?(follower, followee)
unfollow(follower, followee)
else
follow(follower, followee)
end
end
###
# Specifies if a {Follower} object follows a {Followee} object
#
# @param [Follower] follower - the {Follower} object to test against
# @param [Followee] followee - the {Followee} object to test against
# @return [Boolean]
###
def self.follows?(follower, followee)
validate_followee(followee)
validate_follower(follower)
scope_by_follower(follower).scope_by_followee(followee).exists?
end
###
# Retrieves a scope of {Follow} objects filtered by a {Followee} object
#
# @param [Followee] followee - the {Followee} to filter
# @return [ActiveRecord::Relation]
###
def self.scope_by_followee(followee)
where(followee: followee)
end
###
# Retrieves a scope of {Follow} objects filtered by a {Followee} type
#
# @param [Class] klass - the {Class} to filter
# @return [ActiveRecord::Relation]
###
def self.scope_by_followee_type(klass)
where(followee_type: klass.to_s.classify)
end
###
# Retrieves a scope of {Follow} objects filtered by a {Follower} object
#
# @param [Follower] follower - the {Follower} to filter
# @return [ActiveRecord::Relation]
###
def self.scope_by_follower(follower)
where(follower: follower)
end
###
# Retrieves a scope of {Follow} objects filtered by a {Follower} type
#
# @param [Class] klass - the {Class} to filter
# @return [ActiveRecord::Relation]
###
def self.scope_by_follower_type(klass)
where(follower_type: klass.to_s.classify)
end
private
###
# Validates a followee object
#
# @raise [ArgumentError] if the followee object is invalid
###
def self.validate_followee(followee)
raise ArgumentError.new unless followee.respond_to?(:is_followee?) && followee.is_followee?
end
###
# Validates a follower object
#
# @raise [ArgumentError] if the follower object is invalid
###
def self.validate_follower(follower)
raise ArgumentError.new unless follower.respond_to?(:is_follower?) && follower.is_follower?
end
end
end