# ScopedFrom Provides a simple mapping between scopes and controller parameters for [Ruby On Rails 3](http://rubyonrails.org/). ## Installation ### As a gem Just add this into your `Gemfile`: gem 'scoped_from' Then, just run `bundle install`. ### As a plugin From your application path, execute: rails plugin install git://github.com/alexistoulotte/scoped_from.git ## Example First, a model with some scopes: class Post < ActiveRecord::Base scope :commented, where('comments_count > 0') scope :created_between, lambda { |after, before| where('created_at >= ? AND created_at <= ?', after, before) } scope :search, lambda { |pattern| where('body LIKE ?', "%#{pattern}%") } scope :with_category, lambda { |category_id| where(:category_id, category_id) } end After, a controller: class PostsController < ActionController::Base def index @posts = Post.scoped_from(params) end end Then, it just filter your model from params: /posts?commented=1 /posts?search=rails /posts?search=rails&commented=1&with_category=42 ## Accepted scopes All scopes can be mapped with `scoped_from` method **except** scopes taking a `lambda` (or a `Proc`) with an arity greater than 1 (for example: `created_between` in the above code). Scopes with no argument are invoked if parameter value is evaluated as `true`. It includes `"true"`, `"yes"`, `"y"`, `"on"`, and `"1"` strings. ## Scopes restriction You can restrict mapping to some scopes with `:only` option: @posts = Post.scoped_from(params, :only => ['commented', 'search']) You can also exclude some scopes from mapping with `:except` option: @posts = Post.scoped_from(params, :except => 'commented') ## Mapping order If you need to map an SQL order, just pass `order` parameter: @posts = Post.scoped_from(:order => 'created_at') Order direction can be specified using a dot, space or `:` as delimiter: @posts = Post.scoped_from(:order => 'created_at.desc') Note that order is SQL safe with `scoped_from` method (columns names are checked). ## Some cool stuff If your provide an array as parameter value, scope is invoked with each item of the array: @posts = Post.scoped_from(:search => ['bar', 'foo']) is equivalent to @posts = Post.search('bar').search('foo') By default, blank parameter values are ignored, you can include them with `:include_blank` option: @posts = Post.scoped_from(params, :include_blank => true) You may also want to filter on columns, just specify `:include_columns` option: @posts = Post.scoped_from(params, :include_columns => true) A query string can also be given to `scoped_from` method: @posts = Post.scoped_from('with_category=24&search[]=foo&search[]=bar') Returned scope from `scoped_from` method gives access to an internal query object: @posts = Post.scoped_from(params) @query = @posts.query This query provides you some convenience methods like `params`, `order_column` and `order_direction`. This object can also be used to save user's search into a database or other storage system. But, you may also have to subclass this query class. You have to create a subclass of `ScopedFrom::Query` named `#{RecordClassName}Query`. Here is an example: class PostQuery < ScopedFrom::Query def category Category.find_by_id(params[:with_category]) if params[:with_category] end end This class has to be in load path. Then into a view: <% if @query.category %>

All posts of category <%= @query.category.name %>

<% else %>

All posts

<% end %> ## Executing test suite This project is fully tested with [Rspec 2](http://github.com/rspec/rspec). Just run `rake` (after a `bundle install`).