**ranked-model** is a modern row sorting library built for Rails 3. It uses ARel aggressively and is better optimized than most other libraries. [![Build Status](https://travis-ci.org/mixonic/ranked-model.png)](https://travis-ci.org/mixonic/ranked-model) Installation ------------ To install ranked-model, just add it to your `Gemfile`: ``` ruby gem 'ranked-model' # Or pin ranked-model to git # gem 'ranked-model', # :git => 'git@github.com:mixonic/ranked-model.git' ``` Then use `bundle install` to update your `Gemfile.lock`. Simple Use ---------- Use of ranked-model is straight ahead. Get some ducks: ``` ruby class Duck < ActiveRecord::Base end ``` Put your ducks in a row: ``` ruby 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: ``` ruby 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: ``` ruby @duck.update_attribute :row_order_position, 0 # or 1, 2, 37. :first and :last are also valid ``` Position numbers begin at zero. A position number greater than the number of records acts the same as :last. So using a normal json controller where `@duck.attributes = params[:duck]; @duck.save`, JS can look pretty elegant: ``` javascript $.ajax({ type: 'PUT', url: '/ducks', dataType: 'json', data: { duck: { row_order_position: 0 } }, // or whatever your new position is }); ``` Complex Use ----------- The `ranks` method takes serveral arguments: ``` ruby 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: ``` ruby Duck.rank(:row_order) Pond.first.ducks.rank(:swimming_order) Duck.walking.rank(:walking) ``` Internals --------- 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 members of the ranked group. Contributing ------------ Fork, clone, write a test, write some code, commit, push, send a pull request. Github FTW! RankedModel is mostly the handiwork of Matthew Beale: * [madhatted.com](http://madhatted.com) is where I blog. Also [@mixonic](http://twitter.com/mixonic). * [Spinto](http://www.spintoapp.com) is a product I'm bootstrapping. A hearty thanks to these contributors: * [Harvest](http://getharvest.com) where this Gem started. They are great, great folks. * [yabawock](https://github.com/yabawock) * [AndrewRadev](https://github.com/AndrewRadev) * [adheerajkumar](https://github.com/adheerajkumar) * [mikeycgto](https://github.com/mikeycgto)