⭐️ A true Bayesian rating system with scope and cache enabled
Alternatives To Rating
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
319 days ago11January 16, 20201mitRuby
:star: A true Bayesian rating system with scope and cache enabled
a month ago1gpl-3.0Python
A framework for majority vote classifiers allowing for computation of PAC Bayesian risk bounds.
18 years ago10January 22, 20151mitCSS
Rails 3 Bayesian Ratings Gem
Majority Vote Bounds3
4 years agobsd-2-clausePython
PAC-Bayesian bounds computation related to "Risk Bounds for the Majority Vote [...]" (JMLR 2015)
Audit Lab2
5 years ago8mitPython
This repo contains python3 code for running or assisting with post-election audits.
4 years agobsd-3-clausePython
Rating System2
3 years ago4PHP
Q and A up vote/down vote weighted rating system using Bayesian average
Steam Era Goty1
2 months ago2mitPython
SteamEra Games of the Year Awards 2017.
Bayesian Analysis Us 2016 Elections1
2 years agoR
Alternatives To Rating
Select To Compare

Alternative Project Comparisons


CI Gem Version Maintainability codecov Sponsor

A true Bayesian rating system with scope and cache enabled.

JS Rating?

This is Raty: wbotelhos/raty 🌟


Rating uses the know as "True Bayesian Estimate" inspired on IMDb rating with the following formula:

(WR) = (v  (v + m))  R + (m  (v + m))  C

IMDb Implementation:

WR: weighted rating

R: average for the movie (mean) = (Rating)

v: number of votes for the movie = (votes)

m: minimum votes required to be listed in the Top 250

C: the mean vote across the whole report

Rating Implementation:

WR: weighted rating

R: average for the resource

v: number of votes for the resource

m: average of the number of votes

C: the average rating based on all resources


Add the following code on your Gemfile and run bundle install:

gem 'rating'

Run the following task to create the Rating migration:

rails g rating:install

Then execute the migrations to create the to create tables rating_rates and rating_ratings:

rake db:migrate


Just add the callback rating to your model:

class Author < ApplicationRecord

Now this model can vote or receive votes.


You can vote on some resource:

author   = Author.last
resource = Article.last

author.rate resource, 3


A voted resource exposes a cached data about it state:

resource = Article.last


It will return a Rating object that keeps:

average: the normal mean of votes;

estimate: the true Bayesian estimate mean value (you should use this over average);

sum: the sum of votes for this resource;

total: the total of votes for this resource.


You can retrieve the rate of some author gave to some resource:

author   = Author.last
resource = Article.last

author.rate_for resource

It will return a Rate object that keeps:

author: the author of vote;

resource: the resource that received the vote;

value: the value of the vote.


Maybe you want just to know if some author already rated some resource and receive true or false:

author   = Author.last
resource = Article.last

author.rated? resource


All rating received.


It will return a collection of Rate object.


All rating given.


It will return a collection of Rate object.


You can list resource ordered by rating data:


It will return a collection of resource ordered by estimate desc as default. The order column and direction can be changed:

Article.order_by_rating({ column: :average, direction: :asc })

It will return a collection of resource ordered by Rating table data.


All methods support scope query, since you may want to vote on items of a resource instead the resource itself. Let's say an article belongs to one or more categories and you want to vote on some categories of this article.

category_1 = Category.first
category_2 = Category.second
author     = Author.last
resource   = Article.last

In this situation you should scope the vote of article with some category:


author.rate resource, 3, scope: category_1
author.rate resource, 5, scope: category_2

Now resource has a rating for category_1 and another one for category_2.


Recovering the rating values for resource, we have:

# nil

But using the scope to make the right query:

resource.rating scope: category_1
# { average: 3, estimate: 3, sum: 3, total: 1 }

resource.rating scope: category_2
# { average: 5, estimate: 5, sum: 5, total: 1 }


On the same way you can find your rates with a scoped query:

author.rated scope: category_1
# { value: 3, scopeable: category_1 }


The resource still have the power to consult its rates:

article.rates scope: category_1
# { value: 3, scopeable: category_1 }

article.rates scope: category_2
# { value: 3, scopeable: category_2 }


To order the rating you do the same thing:

Article.order_by_rating({ scope: category_1 })

Extra Scopes

Maybe you need to use more than one scope to make a rate, so you can use the extra_scopes options. This feature is enable only to restrict the rate, the rating calculation will ignore it.

Example situation: I have a Profile (resource) that belongs to some Category (scope) and the Client (author) will rate this Profile based on each Lead (extra scope) this Profile made. The Client can vote just one time on each lead, but many times to that Profile. The Profile has a rating score based on all leads made on that Category.

scope    = Category.first
author   = Client.last
resource = Profile.last
lead     = Lead.last

author.rate resource, 5, extra_scopes: { lead_id: lead.id }, scope: scope
  • The extra scopes fields is not present into gem, so you cannot use { lead: lead }, for example.

All methods listed on Scope session allows extra_scopes as additional condition too.


Maybe you want to recover all records with or without scope, so you can add the suffix _records on relations:

category_1 = Category.first
category_2 = Category.second
author     = Author.last
resource   = Article.last

author.rate resource, 1
author.rate resource, 3, scope: category_1
author.rate resource, 5, scope: category_2

# { average: 1, estimate: 1, scopeable: nil       , sum: 1, total: 1 },
# { average: 3, estimate: 3, scopeable: category_1, sum: 3, total: 1 },
# { average: 5, estimate: 5, scopeable: category_2, sum: 5, total: 1 }

# { value: 1 }, { value: 3, scopeable: category_1 }, { value: 5, scopeable: category_2 }

# { value: 1 }, { value: 3, scopeable: category_1 }, { value: 5, scopeable: category_2 }


If you have a model that will only be able to rate but not to receive a rate, configure it as author. An author model still can be rated, but won't genarate a Rating record with all values as zero to warm up the cache.

rating as: :author


Maybe you want include a comment together your rating or even a fingerprint field to make your rating more secure. So, first you will need to add more fields to the Rating::Rate table:

class AddCommentAndFingerprintOnRatingRates < ActiveRecord::Migration
  def change
    add_column :rating_rates, :comment, :text

    add_reference :rating_rates, :fingerprint, foreign_key: true, index: true, null: false

As you can seed, we can add any kind of field we want. Now we just provide this values when we make the rate:

author      = Author.last
resource    = Article.last
comment     = 'This is a very nice rating. s2'
fingerprint = Fingerprint.new(ip: '')

author.rate resource, 3, metadata: { comment: comment, fingerprint: fingerprint }

Now you can have this data into your model normally:

author = Author.last
rate   = author.rates.last

rate.comment     # 'This is a very nice rating. s2'
rate.fingerprint # <Fingerprint id:...>
rate.value       # 3


If you need to warm up a record with scope, you need to setup the scoping relation.

class Resource < ApplicationRecord
  rating scoping: :categories

Now, when a resource is created, the cache will be generated for each related category as scopeable.

Table Name

You can choose the table where Rating will write the data via YAML config. You should just to provide a config/rating.yml file with the following content:

  rate_table: reviews
  rating_table: review_ratings

Now the rates will be written on reviews table over rating_rates and calculation will be on review_ratings over rating_ratings. You can change one table o both of them.


Rate Uniqueness

Since you can to use Extra Scopes to restrict rates and the original model Rating::Rate is inside gem, you can configure the uniqueness validation, from outside, to include this extra scopes.

        case_sensitive: false

          - author_type
          - resource_id
          - resource_type
          - scopeable_id
          - scopeable_type
          - scope_1
          - scope_2

Unscoped Rating

All rating values are grouped by its own scope, but you can disable it and group all of them together.

rating unscoped_rating: true

author   = User.last
resource = Article.last
scope    = Category.last

author.rate resource, 1, scope: scope
author.rate resource, 2, scope: scope
author.rate resource, 3

Now the sum will be 6 and the total will be 3 because all rating will be calculated into just one rating record ignoring the scopeable object. The rating record is always saved on the record with scopeable as nil.


The where option can be used to filter the Rating::Rate records used to create the final Rating::Rating. You can filter only approved rates, for exemplo:

rating where: 'approved = true'

author   = User.last
resource = Article.last

author.rate resource, 1, extra_scope: { approved: false }
author.rate resource, 5, extra_scope: { approved: true }

As you can see, now, only the rate with value 5 will be included on the final rating.


To run all specs, run the following rakes:

bundle exec rake spec
bundle exec rake spec_config
bundle exec rake spec_config_with_extra_scopes


Popular Bayesian Projects
Popular Vote Projects
Popular Machine Learning Categories
Related Searches

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.