Easily implement search forms and column ordering based on your models scopes
Clone or download
Pull request Compare This branch is 3 commits behind novagile:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



ScopedSearch is a plugin to easily create search forms and do column ordering.
It is written specifically for Rails 3 and is compatible with both ActiveRecord and Mongoid.

ScopeSearch is Copyright © 2010 Novagile, written by Nicolas Blanco


I’ve begun writing this plugin because I really like Searchlogic from Ben Johnson.
I was using it in all my Rails 2 Active Record projects.

Searchlogic has a feature that dynamically adds a lot of scopes in your models. But a feature from Searchlogic I really like is the ability to create an object
that binds to your models scopes and being able to use it directly in a form. You can add many fields in your search forms, and the controller stays
the same. I really wanted the same behaviour in Rails 3 and compatible with both ActiveRecord and Mongoid.


For now, ScopedSearch is under development.
You may use it as plugin or as a gem.


Edit your Gemfile and add :

  gem 'scoped-search', :require => "scoped_search"


  rails plugin install git://github.com/novagile/scoped-search.git

ScopedSearch does not dynamically include itself in ActiveRecord or Mongoid, you have to include it in your models where you want to use it.

Simply include the ScopedSearch::Model module in your models like this…

  class Post < ActiveRecord::Base
    include ScopedSearch::Model
    scope :retrieve, lambda { |q| where("title like ?", "%#{q}%") }
    scope :state_equals, lambda { |state| where( {:state => state }) }
    scope :published, where(:published => true)

In your ApplicationHelper, include the ScopedSearch::Helpers module :

  module ApplicationHelper
    include ScopedSearch::Helpers

Console testing

You can test the search object in a console!

  > search = Post.scoped_search
   => #<ScopedSearch::Base...>
  > search.count
   => 4
  > search.all.map(&:body)
   => ["test", "lalala", "foo", "bar"] 
  > search.retrieve = "foo"
   => "foo"
  > search.count
   => 1 
  > search.all
   => [#<Post id: 3, title: nil, body: "foo"...]


Then in your controller you can do like this :

  class PostsController < ApplicationController
    def index
      @search = Post.scoped_search(params[:search])
      @posts = @search.all # or @search.paginate(...), or you can even continue the scope chain ! Just add your scopes like this : @search.build_relation.other_scope.other_other_scope... :)

In your view, you can create a form that takes your search object as parameter, like this :

  <%= form_for @search do |f| %>
    <%= f.text_field :retrieve %>
    <%= f.select :state_equals, ["pending", "accepted", "deleted"] %>
    <%= submit_tag "Search" %>
  <% end %>

Column ordering

You want to get column ordering for free? Sure!
In your model, use the scoped_order method like this :

  class Post < ActiveRecord::Base
    scoped_order :title, created_at, :updated_at # , ...

It will add two scopes for each column, named “ascend_by_column_name” and “descend_by_column_name” (like Searchlogic).

Then in your views, you may use the order_for_scoped_search view helper like this :

      <th><%= link_to "Title", order_for_scoped_search(:title) %></th>

Scopes with no arguments and excluded scopes

If a scope attribute in the ScopedSearch object has a value that equals to “true”, the scope will be chained without any parameters.
If the scope attribute has a value that is blank? or equals to “false”, the scope will be rejected and won’t be chained in the search.

Example :

  search = User.scoped_search({ :accepted => "true", :rejected => "", :refused => "false", :has_email => ["foo@bar.com", "bar@foo.com"] })

  search.all # => results in User.accepted.has_email(["foo@bar.com", "bar@foo.com"])

Issue with single Array attribute and multi parameters scopes

When you define a scope, you may define it with a single value that accepts an array, or as a multi parameters scope.
But I haven’t found an easy way yet to know the number of parameters a scope accepts (if you know, please tell me!).
So, for now, if you pass an array to a scoped attribute, it will be passed as an array to the scope.
If you set attributename_multi_params to true, it will be passed as multiple params to the scope.

Example :

  class Post < ActiveRecord::Base
    scope :retrieve_in_title_and_body, lambda { |a, b| where("title like ? and body like ?", "%#{a}%", "%#{b}") }
    scope :retrieve_ids, lambda { |ids| where(:id => ids) }
  # For a multi params scope
  > search = Post.scoped_search
  > search.retrieve_in_title_and_body = ["test", "whaaaa"]
  > search.retrieve_in_title_and_body_multi_params = true
  # For an Array param
  > search.retrieve_ids = [1,2,3]  


This plugin is new and under development, patches and contributions are welcome! Please fork and make pull requests, thanks!