ryanto/acts_as_votable

View on GitHub
lib/acts_as_votable/voter.rb

Summary

Maintainability
A
30 mins
Test Coverage
# frozen_string_literal: true

module ActsAsVotable
  module Voter
    def self.included(base)
      # allow user to define these
      aliases = {
        vote_up_for: [:likes, :upvotes, :up_votes],
        vote_down_for: [:dislikes, :downvotes, :down_votes],
        unvote_for: [:unlike, :undislike],
        voted_on?: [:voted_for?],
        voted_up_on?: [:voted_up_for?, :liked?],
        voted_down_on?: [:voted_down_for?, :disliked?],
        voted_as_when_voting_on: [:voted_as_when_voted_on, :voted_as_when_voting_for, :voted_as_when_voted_for],
        find_up_voted_items: [:find_liked_items],
        find_down_voted_items: [:find_disliked_items]
      }

      base.class_eval do

        has_many :votes, class_name: "ActsAsVotable::Vote", as: :voter, dependent: :delete_all do
          def votables
            includes(:votable).map(&:votable)
          end
        end

        aliases.each do |method, links|
          links.each do |new_method|
            alias_method(new_method, method)
          end
        end

      end
    end

    # voting
    def vote(args)
      args[:votable].vote_by args.merge(voter: self)
    end

    def vote_up_for(model = nil, args = {})
      vote votable: model, vote_scope: args[:vote_scope], vote: true
    end

    def vote_down_for(model = nil, args = {})
      vote votable: model, vote_scope: args[:vote_scope], vote: false
    end

    def unvote_for(model, args = {})
      model.unvote voter: self, vote_scope: args[:vote_scope]
    end

    # results
    def voted_on?(votable, args = {})
      votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
                         vote_scope: args[:vote_scope])
      votes.exists?
    end

    def voted_up_on?(votable, args = {})
      votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
                         vote_scope: args[:vote_scope], vote_flag: true)
      votes.exists?
    end

    def voted_down_on?(votable, args = {})
      votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
                         vote_scope: args[:vote_scope], vote_flag: false)
      votes.exists?
    end

    def voted_as_when_voting_on(votable, args = {})
      vote = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
                         vote_scope: args[:vote_scope]).select(:vote_flag).last
      return nil unless vote
      return vote.vote_flag
    end

    def find_votes(extra_conditions = {})
      votes.where(extra_conditions)
    end

    def find_up_votes(args = {})
      find_votes vote_flag: true, vote_scope: args[:vote_scope]
    end

    def find_down_votes(args = {})
      find_votes vote_flag: false, vote_scope: args[:vote_scope]
    end

    def find_votes_for_class(klass, extra_conditions = {})
      find_votes extra_conditions.merge(votable_type: klass.name)
    end

    def find_up_votes_for_class(klass, args = {})
      find_votes_for_class klass, vote_flag: true, vote_scope: args[:vote_scope]
    end

    def find_down_votes_for_class(klass, args = {})
      find_votes_for_class klass, vote_flag: false, vote_scope: args[:vote_scope]
    end

    # Including polymporphic relations for eager loading
    def include_objects
      ActsAsVotable::Vote.includes(:votable)
    end

    def find_voted_items(extra_conditions = {})
      options = extra_conditions.merge voter_id: id, voter_type: self.class.base_class.name
      include_objects.where(options).collect(&:votable)
    end

    def find_up_voted_items(extra_conditions = {})
      find_voted_items extra_conditions.merge(vote_flag: true)
    end

    def find_down_voted_items(extra_conditions = {})
      find_voted_items extra_conditions.merge(vote_flag: false)
    end

    def get_voted(klass, extra_conditions = {})
      klass.joins(:votes_for).merge find_votes(extra_conditions)
    end

    def get_up_voted(klass)
      klass.joins(:votes_for).merge find_up_votes
    end

    def get_down_voted(klass)
      klass.joins(:votes_for).merge find_down_votes
    end
  end
end