Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Rankeable allows you to easily add rankings to your Rails applications
Ruby JavaScript
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
app/models
lib
spec
.gitignore
.rspec
.travis.yml
Gemfile
Gemfile.lock
MIT-LICENSE
README.md
Rakefile
rankeable.gemspec

README.md

Rankeable

Build Status

Rankeable is a ranking system for Rails applications

Rankeable allows you to easily add rankings to your models in a Rails application. It's geared towards rankings that are too expensive to calculate on the request cycle, and must be calculated periodically in the background.

Any object can be ranked, and any number of different rankings can be created, with different ranking rules.

Documentation

You can view the Survey documentation in RDoc format here:

http://rubydoc.info/github/runtimerevolution/rankeable/frames

Main Features:

  • A flexible model allowing any object to be ranked
  • Multiple rankings and ranking rules
  • Easy integration with delayed_job, sidekiq and resque for background calculation

Installation

Add Rankeable to your Gemfile:

gem 'rankeable', :git => 'git://github.com/runtimerevolution/rankeable.git'

Then run bundle to install the Gem:

bundle install

Now generate and run migrations:

rails generate survey:install
bundle exec rake db:migrate

After installation Rankeable generates a RankingsRules class inside of ranking_concerns folder (you can change the location of RankingRules class. The only constraint is the existence of RankingRules in your application).

Getting Started

For example, using the context of a Game that have many players and referees.

class Game < ActiveRecord::Base
    has_rankings
    has_many :players
    has_many :referees

    # ...
end

class Player < ActiveRecord::Base
    is_rankeable

    # ...
end

class Referee < ActiveRecord::Base
    is_rankeable
    # ...
end

How Ranking works

Ranking has some important components:

  • rankeable: the owner of the rankings (in our example it's Game). Contextualizes the ranking
  • ranked_type: The ranked model
  • ranked_call: The calculation function that actually ranks objects

Creating rankings

Add a ranking and ranking rule that ranks players by number of goals scored:

# creating ranking with rule "number_of_goals"
@game.rankings.create(:name => "goals_by_player",
    :ranked_type => "Player", :ranked_call => "number_of_goals")

# in file app/ranking_concerns/ranking_rules.rb

# Rule Number of Goals
def number_of_goals(ranking, *args)
    ranking.rankeable.players.order("goals DESC").map do |player|
        OpenStruct.new(:value => player.goals,
            :ranked_object => player, :label => "#{player.name} - #{player.number}")
    end
end

Add a ranking and ranking rule that ranks players by the number of faults:

# creating ranking with rule "number_of_faults"
@game.rankings.create(:name => "faults_by_refeere",
    :ranked_type => "Refeere", :ranked_call => "number_of_faults")

# in file app/ranking_concerns/ranking_rules.rb

# Rule Number of Faults
def number_of_faults(ranking, *args)
    ranking.rankeable.refeeres.map { |refeere|
        total_faults = refeere.red_cards + refeere.yellow_cards
        OpenStruct.new(:value => total_faults,
            :ranked_object => player, :label => refeere.name)
    }.sort {|a,b| b.value <=> a.value }
end

Ranking Rules Protocol

Every Ranking Rule must return a collection with objects that respond to:

  • label => a label describing the object ranked
  • ranked_object => The target object of the ranking
  • value => The value calculated on Ranking rule (something that can be converted to a float)

See Rankeable Working

# find our number_of_goals strategy for this game
ranking = Game.first.rankings.find_by_name("goals_by_player")

#calculate our rankings
ranking.calculate

# show the results
ranking.values
=> [#<RankingValue position=1, value=2, ranked_object=#<Player id: 13, name: "Chuck Norris", goals: 2, created_at: "2013-01-31 14:48:54", updated_at: "2013-01-31 14:48:54">>,
#<RankingValue position=2, value=1, ranked_object=#<User id: 8, name: "Bob", goals: 1, created_at: "2013-01-31 14:48:54", updated_at: "2013-01-31 14:48:54">>]

# What's the position of a particular player in the ranking ?
ranking.ranked_item_position(Player.find_by_name('Chuck Norris'))
=> 25

Help your migrations

Rankeable help us with migrations.

To create a model with rankings you can use has_rankings option, but if you want a model who is the target of your ranking use is_rankeable option instead. This will create the model (if one doesn't exist) and configure it with default Rankeable Modules.

# creating Game Model
rails g has_rankings game name:string
# creating Player Model
rails g is_rankeable player name:string number:integer goals:integer
# creating Referee Model
rails g is_rankeable referee name:string number_of_faults:integer yellow_cards:integer red_cards:integer

This is the scafold generated by the Rankeable migration helper. Next, you must run the migrate command in order to the changes take the effect.

Integration with delayed_job and others

Usually rankings need to be calculated in the background, using something like delayed_job, sidekiq or resque.

An example using delayed_job:

rank_scores_for_refeeres = @game.rankings.where(:ranked_call => "number_of_goals",
    :ranked_type => "Refeere").first
rank_scores_for_refeeres.delay.calculate

License

Copyright © 2013 Runtime Revolution, released under the MIT license.

githalytics.com alpha

Something went wrong with that request. Please try again.