ranked-model is a modern row sorting library built for Rails 3. It uses ARel aggressively and is better optimized than most other libraries.
To install ranked-model, just add it to your Gemfile
:
gem 'ranked-model'
# Or pin ranked-model to git
# gem 'ranked-model',
# :git => '[email protected]:harvesthq/ranked-model.git'
Then use bundle install
to update your Gemfile.lock
.
Use of ranked-model is straight ahead. Get some ducks:
class Duck < ActiveRecord::Base
end
Put your ducks in a row:
class Duck < ActiveRecord::Base
include RankedModel
ranks :row_order
end
This simple example assumes an integer column called row_order
. To order Ducks by this order:
Duck.rank(:row_order).all
The ranking integers stored in the row_order
column will be big and spaced apart. When you
implement a sorting UI, just update the resource with the position instead:
@duck.update_attribute :row_order_position, 0 # or 1, 2, 37. :first and :last are also valid
So using a normal json controller where @duck.attributes = params[:duck]; @duck.save
, JS can
look pretty elegant:
$.ajax({
type: 'PUT',
url: '/ducks',
dataType: 'json',
data: { duck: { row_order_position: 0 } }, // or whatever your new position is
});
The ranks
method takes serveral arguments:
class Duck < ActiveRecord::Base
include RankedModel
ranks :row_order, # Name this ranker, used with rank()
:column => :sort_order # Override the default column, which defaults to the name
belongs_to :pond
ranks :swimming_order,
:with_same => :pond_id # Ducks belong_to Ponds, make the ranker scoped to one pond
scope :walking, where(:walking => true )
ranks :walking_order,
:scope => :walking # Narrow this ranker to a scope
end
When you make a query, add the rank:
Duck.rank(:row_order)
Pond.first.ducks.rank(:swimming_order)
Duck.walking.rank(:walking)
This libarary is written using ARel from the ground-up. This leaves the code much cleaner than many implementations. ranked-model is also optimized to write to the database as little as possible: ranks are stored as a number between -8388607 and 8388607 (the MEDIUMINT range in MySQL). When an item is given a new position, it assigns itself a rank number between two neighbors. This allows several movements of items before no digits are available between two neighbors. When this occurs, ranked-model will try to shift other records out of the way. If items can't be easily shifted anymore, it will rebalance the distribution of rank numbers across all memebers of the ranked group.
Fork, clone, write a test, write some code, commit, push, send a pull request. Github FTW!
This project was open-sourced by Harvest. We're hiring!
A hearty thanks to these contributors: