lib/partisan/follow.rb
module Partisan
module Follow
extend ActiveSupport::Concern
# Constants
FOLLOWER_FOLLOW_ACCESSORS = [:about_to_follow, :just_followed]
FOLLOWER_UNFOLLOW_ACCESSORS = [:about_to_unfollow, :just_unfollowed]
FOLLOWABLE_BEING_FOLLOWED_ACCESSORS = [:about_to_be_followed_by, :just_followed_by]
FOLLOWABLE_BEING_UNFOLLOWED_ACCESSORS = [:about_to_be_unfollowed_by, :just_unfollowed_by]
included do
# Validations
validates :followable, presence: true
validates :follower, presence: true
# Associations
belongs_to :followable, polymorphic: true
belongs_to :follower, polymorphic: true
# Callbacks
after_create :update_follow_counter
after_destroy :update_follow_counter
around_create :around_create_follower
around_create :around_create_followable
around_destroy :around_destroy_follower
around_destroy :around_destroy_followable
end
protected
def update_follow_counter
follower.update_followings_counter
followable.update_followers_counter
end
def around_create_follower(&blk)
execute_callback :follower, :follow, &blk
end
def around_create_followable(&blk)
execute_callback :followable, :being_followed, &blk
end
def around_destroy_follower(&blk)
execute_callback :follower, :unfollow, &blk
end
def around_destroy_followable(&blk)
execute_callback :followable, :being_unfollowed, &blk
end
private
def execute_callback(association, callback, &blk)
# Fetch our associated objects
object = send(association)
reverse_object = association == :follower ? send(:followable) : send(:follower)
# Associate each given accessor to the reverse object
accessors = self.class.accessors_for_follow_callback(association, callback)
accessors.map { |accessor| object.send "#{accessor}=", reverse_object }
# Run the callbacks
object.run_callbacks(callback, &blk)
# Reset each accessor value
accessors.map { |accessor| object.send "#{accessor}=", nil }
true
end
module ClassMethods
def accessors_for_follow_callback(association, callback)
const_get "#{association}_#{callback}_accessors".upcase
end
end
end
end