Easily search you ActiveRecord models using a named_scope - modified to define multiple named scopes, and optionally take a list of fields at query time
Ruby
Pull request Compare This branch is 4 commits ahead, 520 commits behind wvanbergen:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
lib
tasks
test
.gitignore
LICENSE
README.rdoc
Rakefile
init.rb
scoped_search.gemspec

README.rdoc

scoped_search

The scoped_search Rails plugin makes it easy to search your ActiveRecord models. Searching is performed using a query string, which should be passed to the named_scope search_for that uses SQL LIKE %keyword% conditions for searching (ILIKE for Postgres). You can specify what fields should be used for searching.

Installing

The recommended method to enable scoped_search in your project is adding the scoped_search gem to your environment. Add the following code to your Rails configuration in config/environment.rb:

Rails::Initializer.run do |config|
  ...
  config.gem 'wvanbergen-scoped_search', :lib => 'scoped_search', 
                 source => 'http://gems.github.com/'
end

Run sudo rake gems:install to install the gem.

Another alternative is to install scoped_search as a Rails plugin:

script/plugin install git://github.com/wvanbergen/scoped_search.git

Usage

First, you have to specify what columns should be searched:

class User < ActiveRecord::Base
  searchable_on :first_name, :last_name
end

Now, the search_for scope is available for queries. You should pass a query string to the scope. This can be empty or nil, in which case all no search conditions are set (and all records will be returned).

User.search_for(params[:q]).each { |project| ... }

While search_for is the default named search scope, you can define multiple scopes by naming them in other ways:

class User < ActiveRecord::Base

  searchable_on do
    scope :name_search
    fields :first_name, :last_name
  end

  searchable_on do
    scope :login_search
    fields :login, :email
  end

  # this is an alternative way to create the previous search scope

  acts_as_scoped_search :login_search, :login, :email
end

Note that because all of the above provided names for the search scopes, search_for has not been defined. This is useful if some other plugin or your own code has already defined a search_for method.

If you'd rather select the columns to search at runtime, you can do that with the default “scoped_search” scope created when you invoke “acts_as_scoped_search” or “searchable_on” in any way. It's the most general method provided.

class User < ActiveRecord::Base
  # Creates a default scope called :scoped_search which takes 
  # the keyword string, and a list of fields
  acts_as_scoped_search 

  # you can use the scoped_search scope to build another named_scope
  named_scope :search_text_fields, lambda { |keywords| 
    scoped_search(keywords, :login, :email, :first_name, :last_name).
       scoped(:order => 'users.id DESC')
  }

  # or from a method
  def user_logins_from_search(keywords)
     User.scoped_search(keywords, :login, :email, :first_name, :last_name).
       scoped(:order => 'users.id DESC').map &:login
  end
end

Finally, you can specify additional columns to search in a named scoped_search when you invoke it. The additional columns will only be used for that one query. For example:

class User < ActiveRecord::Base

  searchable_on :login, :email

  # you can use a named scoped search to build another search scope
  # by adding columns - the scope below will search on all 4 text
  # fields

  named_scope :search_text_fields, lambda { |keywords| 
       search_for(keywords, :first_name, :last_name)
  }

end

You can also search on associate models. This works with belongs_to, has_one, has_many, has_many :through, and HABTM. For example if a User has_many Notes (title, content, created_at, updated_at)

class User < ActiveRecord::Base
  has_many: notes
  searchable_on :first_name, :last_name, :notes_title, :notes_content
end

The search query language is simple. It supports these constructs:

  • words: some search keywords

  • phrases: "a single search phrase"

  • negation: "look for this" -"but do not look for this phrase and this" -word

  • OR words/phrases: word/phrase OR word/phrase. Example: "Hello World" OR "Hello Moon"

  • dates: mm/dd/yyyy, dd/mm/yyyy, yyyy/mm/dd, yyyy-mm-dd

  • date ranges: > date, >= date, < date, <= date, date TO date. Examples: > 30/05/1983, < 2009-01-30

This functionality is build on named_scope. The searchable_on statement creates a named_scope search_for. Because of this, you can actually chain the call with other scopes. For example, this can be very useful if you only want to search in projects that are accessible by a given user.

class Project < ActiveRecord::Base
  searchable_on :name, :description
  named_scope :accessible_by, lambda { |user| ... }
end

# using chained named_scopes and will_paginate
Project.accessible_by(current_user).search_for(params[:q]).paginate(:page => params[:page], :include => :tasks)

Additional resources

License

This plugin is released under the MIT license. Please contact weshays (github.com/weshays) or wvanbergen (github.com/wvanbergen) for any questions.