Module: Ballot::Votable

Defined in:
lib/ballot/votable.rb

Overview

Methods added to a model that is marked as a Votable.

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#ballot_registered?Boolean

Indicate whether a ballot has been registered on the current instance of this model. Votes are registered if and only if the vote is a change from the previous vote.

post = Post.create(title: 'my amazing post')
copy = post.dup
post.down_ballot_by current_user
post.ballot_registered? # => true
copy.up_ballot_by current_user # => true
copy.up_ballot_by_current_user # => false
post.ballot_registered? # => true

Returns:

  • (Boolean)


28
29
30
# File 'lib/ballot/votable.rb', line 28

def ballot_registered?
  @ballot_registered
end

#ballot_score(scope = nil, skip_cache: false) ⇒ Object

The computed score of ballots cast (total positive ballots less total negative ballots) for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached score.



341
342
343
344
345
346
347
348
# File 'lib/ballot/votable.rb', line 341

def ballot_score(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['score'].to_i
  else
    total_up_ballots(scope, skip_cache: skip_cache) -
      total_down_ballots(scope, skip_cache: skip_cache)
  end
end

#ballot_voters(*conds, &block) ⇒ Object

Returns the Voter objects that have made votes on this Votable. Additional query conditions may be specified in conds, or in the block if supported by the ORM. The Voter objects are eager loaded to minimize the number of queries required to satisfy this request.

ActiveRecord

Polymorphic eager loading is directly supported, using ballots_for.includes(:voter). Normal where-clause conditions may be provided in conds.

Sequel

Polymorphic eager loading is not supported by Sequel, but has been implemented in Ballot for this method. Normal where-clause conditions may be provided in conds or in block for Sequel virtual row support.



242
243
244
# File 'lib/ballot/votable.rb', line 242

def ballot_voters(*conds, &block)
  __eager_ballot_voters(find_ballots_for(*conds, &block))
end

#down_ballot_by(voter = nil, kwargs = {}) ⇒ Object

Records a negative vote by the provided voter with options provided in kwargs. Any value passed to the vote keyword argument will be ignored. See #ballot_by for more details.



79
80
81
# File 'lib/ballot/votable.rb', line 79

def down_ballot_by(voter = nil, kwargs = {})
  ballot_by(voter, kwargs.merge(vote: false))
end

#down_ballot_by?(voter = nil, kwargs = {}) ⇒ Boolean

Returns true if the provided voter has made negative votes for this Votable. Any value passed to the vote keyword argument will be ignored. See #ballot_by? for more details.

Returns:

  • (Boolean)


195
196
197
# File 'lib/ballot/votable.rb', line 195

def down_ballot_by?(voter = nil, kwargs = {})
  ballot_by?(voter, kwargs.merge(vote: false))
end

#down_ballot_voters(*conds, &block) ⇒ Object

Returns the Voter objects that have made negative votes on this Votable. See #ballot_voters for how conds and block apply.



258
259
260
261
262
# File 'lib/ballot/votable.rb', line 258

def down_ballot_voters(*conds, &block)
  __eager_ballot_voters(
    find_ballots_for(*conds, &block).where(vote: false)
  )
end

#down_ballots_by_class(model_class, kwargs = {}) ⇒ Object

Find negative ballots cast by this Voter matching the canonical name of the model_class as the type of Voter. Any value passed to the vote keyword argument will be ignored. See #ballots_by_class for more details.



225
226
227
# File 'lib/ballot/votable.rb', line 225

def down_ballots_by_class(model_class, kwargs = {})
  ballots_by_class(model_class, kwargs.merge(vote: false))
end

#down_ballots_for(scope: nil) ⇒ Object

Returns ballots for this Votable where the recorded vote is negative.

ActiveRecord

There are no special notes for ActiveRecord.

Sequel

This method returns the dataset; if vote objects are desired, use down_ballots_for.all.



148
149
150
# File 'lib/ballot/votable.rb', line 148

def down_ballots_for(scope: nil)
  find_ballots_for(vote: false, scope: scope)
end

#initializeObject

If the model is caching the ballot summary (in a JSON-serialized column called cached_ballot_summary), we want to ensure that it is initialized to a Hash if it is not set.



11
12
13
14
# File 'lib/ballot/votable.rb', line 11

def initialize(*)
  super
  self.cached_ballot_summary ||= {} if caching_ballot_summary?
end

#total_ballots(scope = nil, skip_cache: false) ⇒ Object

The total number of ballots cast for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached total.



296
297
298
299
300
301
302
# File 'lib/ballot/votable.rb', line 296

def total_ballots(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['total'].to_i
  else
    find_ballots_for(scope: scope).count
  end
end

#total_down_ballots(scope = nil, skip_cache: false) ⇒ Object

The total number of negative ballots cast for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached total.



326
327
328
329
330
331
332
# File 'lib/ballot/votable.rb', line 326

def total_down_ballots(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['down'].to_i
  else
    down_ballots_for(scope: scope).count
  end
end

#total_up_ballots(scope = nil, skip_cache: false) ⇒ Object

The total number of positive ballots cast for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached total.



311
312
313
314
315
316
317
# File 'lib/ballot/votable.rb', line 311

def total_up_ballots(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['up'].to_i
  else
    up_ballots_for(scope: scope).count
  end
end

#up_ballot_by(voter = nil, kwargs = {}) ⇒ Object

Records a positive vote by the provided voter with options provided in kwargs. Any value passed to the vote keyword argument will be ignored. See #ballot_by for more details.



71
72
73
# File 'lib/ballot/votable.rb', line 71

def up_ballot_by(voter = nil, kwargs = {})
  ballot_by(voter, kwargs.merge(vote: true))
end

#up_ballot_by?(voter = nil, kwargs = {}) ⇒ Boolean

Returns true if the provided voter has made positive votes for this Votable. Any value passed to the vote keyword argument will be ignored. See #ballot_by? for more details.

Returns:

  • (Boolean)


187
188
189
# File 'lib/ballot/votable.rb', line 187

def up_ballot_by?(voter = nil, kwargs = {})
  ballot_by?(voter, kwargs.merge(vote: true))
end

#up_ballot_voters(*conds, &block) ⇒ Object

Returns the Voter objects that have made positive votes on this Votable. See #ballot_voters for how conds and block apply.



249
250
251
252
253
# File 'lib/ballot/votable.rb', line 249

def up_ballot_voters(*conds, &block)
  __eager_ballot_voters(
    find_ballots_for(*conds, &block).where(vote: true)
  )
end

#up_ballots_by_class(model_class, kwargs = {}) ⇒ Object

Find positive ballots cast by this Voter matching the canonical name of the model_class as the type of Voter. Any value passed to the vote keyword argument will be ignored. See #ballots_by_class for more details.



217
218
219
# File 'lib/ballot/votable.rb', line 217

def up_ballots_by_class(model_class, kwargs = {})
  ballots_by_class(model_class, kwargs.merge(vote: true))
end

#up_ballots_for(scope: nil) ⇒ Object

Returns ballots for this Votable where the recorded vote is positive.

ActiveRecord

There are no special notes for ActiveRecord.

Sequel

This method returns the dataset; if vote objects are desired, use up_ballots_for.all.



138
139
140
# File 'lib/ballot/votable.rb', line 138

def up_ballots_for(scope: nil)
  find_ballots_for(vote: true, scope: scope)
end

#weighted_ballot_average(scope = nil, skip_cache: false) ⇒ Object

The weighted average of ballots cast (the weighted ballot score over the total number of votes cast) for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached average.



389
390
391
392
393
394
395
396
397
# File 'lib/ballot/votable.rb', line 389

def weighted_ballot_average(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['weighted_ballot_average'].to_i
  elsif (count = total_ballots) > 0
    weighted_ballot_score.to_f / count
  else
    0.0
  end
end

#weighted_ballot_score(scope = nil, skip_cache: false) ⇒ Object

The weighted score of ballots cast (the sum of all positive ballot weights less the sum of all negative ballot weights) for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached score.



373
374
375
376
377
378
379
380
# File 'lib/ballot/votable.rb', line 373

def weighted_ballot_score(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['weighted_ballot_score'].to_i
  else
    up_ballots_for(scope: scope).sum(:weight).to_i -
      down_ballots_for(scope: scope).sum(:weight).to_i
  end
end

#weighted_ballot_total(scope = nil, skip_cache: false) ⇒ Object

The weighted total of ballots cast (the sum of all ballot weights) for this Votable in the provided scope. If scope is not provided, reports for the default scope.

If the Votable has a cached_ballot_summary column and skip_cache is false, returns the cached score.



357
358
359
360
361
362
363
# File 'lib/ballot/votable.rb', line 357

def weighted_ballot_total(scope = nil, skip_cache: false)
  if !skip_cache && caching_ballot_summary?
    scoped_cache_summary(scope)['weighted_ballot_total'].to_i
  else
    find_ballots_for(scope: scope).sum(:weight).to_i
  end
end