0.0
Low commit activity in last 3 years
No release in over a year
Provides a simple mapping between Active Record scopes and controller parameters for Ruby On Rails 4
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 7.0.0, < 8.0.0
>= 3.2.0, < 12.0.0
>= 10.3.0, < 14.0.0
>= 3.1.0, < 3.11.0
>= 1.25.0, < 2.0.0
>= 0.6.0, < 1.0.0
>= 2.8.0, < 3.0.0
>= 1.3.0, < 1.4.0

Runtime

>= 7.0.0, < 8.0.0
>= 7.0.0, < 8.0.0
 Project Readme

ScopedFrom

Provides a simple mapping between scopes and controller parameters for Ruby On Rails 5.

Installation

Just add this into your Gemfile:

gem 'scoped_from'

Then, just run bundle install.

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.

Columns are also automatically scoped.

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')

You may also not want to filter on columns, just specify :exclude_columns option:

@posts = Post.scoped_from(params, exclude_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 %>
  <p>All posts of category <%= @query.category.name %></p>
<% else %>
  <p>All posts</p>
<% end %>

Executing test suite

This project is fully tested with Rspec 3. Just run bundle exec rake (after a bundle install).