lib/voting/models/voting/voting.rb
# frozen_string_literal: true
module Voting
class Voting < ActiveRecord::Base
self.table_name = 'voting_votings'
belongs_to :resource, polymorphic: true
belongs_to :scopeable, polymorphic: true
validates :estimate, :negative, :positive, :resource, presence: true
validates :estimate, numericality: true
validates :negative, :positive, numericality: { greater_than_or_equal_to: 0, only_integer: true }
validates :resource_id, uniqueness: {
case_sensitive: false,
scope: %i[resource_type scopeable_id scopeable_type]
}
class << self
def values_data(resource, scopeable)
sql = %(
SELECT
COALESCE(SUM(negative), 0) voting_negative,
COALESCE(SUM(positive), 0) voting_positive
FROM #{vote_table_name}
WHERE resource_type = ? and resource_id = ? and #{scope_query(scopeable)}
).squish
values = [sql, resource.class.name, resource.id]
values += [scopeable.class.name, scopeable.id] unless scopeable.nil?
execute_sql values
end
def update_voting(resource, scopeable)
record = find_or_initialize_by(resource: resource, scopeable: scopeable)
values = values_data(resource, scopeable)
record.estimate = estimate(values)
record.negative = values.voting_negative
record.positive = values.voting_positive
record.save!
end
private
def estimate(values)
sum = values.voting_negative + values.voting_positive
return 0 if sum.zero?
square = Math.sqrt((values.voting_negative * values.voting_positive) / sum + 0.9604)
((values.voting_positive + 1.9208) / sum - 1.96 * square / sum) / (1 + 3.8416 / sum)
end
def execute_sql(sql)
Vote.find_by_sql(sql).first
end
def vote_table_name
@vote_table_name ||= Vote.table_name
end
def scope_query(scopeable)
return 'scopeable_type is NULL and scopeable_id is NULL' if scopeable.nil?
'scopeable_type = ? and scopeable_id = ?'
end
end
end
end