# ScopedFrom Provides a simple mapping between scopes and controller parameters for [Ruby On Rails 5](http://rubyonrails.org/). ## Installation Just add this into your `Gemfile`: ```ruby gem 'scoped_from' ``` Then, just run `bundle install`. ## Example First, a model with some scopes: ```ruby 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: ```ruby 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. Columns are also automatically scoped. ## Scopes restriction You can restrict mapping to some scopes with `:only` option: ```ruby @posts = Post.scoped_from(params, only: ['commented', 'search']) ``` You can also exclude some scopes from mapping with `:except` option: ```ruby @posts = Post.scoped_from(params, except: 'commented') ``` ## Mapping order If you need to map an SQL order, just pass `order` parameter: ```ruby @posts = Post.scoped_from(order: 'created_at') ``` Order direction can be specified using a dot, space or `:` as delimiter: ```ruby @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: ```ruby @posts = Post.scoped_from(search: ['bar', 'foo']) ``` is equivalent to ```ruby @posts = Post.search('bar').search('foo') ``` You may also not want to filter on columns, just specify `:exclude_columns` option: ```ruby @posts = Post.scoped_from(params, exclude_columns: true) ``` A query string can also be given to `scoped_from` method: ```ruby @posts = Post.scoped_from('with_category=24&search[]=foo&search[]=bar') ``` Returned scope from `scoped_from` method gives access to an internal query object: ```ruby @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: ```ruby 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: ```erb <% if @query.category %>
All posts of category <%= @query.category.name %>
<% else %>All posts
<% end %> ``` ## Executing test suite This project is fully tested with [Rspec 3](http://github.com/rspec/rspec). Just run `bundle exec rake` (after a `bundle install`).