mirego/partisan

View on GitHub
lib/partisan/follow.rb

Summary

Maintainability
A
0 mins
Test Coverage
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