A couple of minutes ago I released scoped_search, a Rails/ActiveRecord plugin that makes it easy to search your models. It is very easy to use:
Install the plugin in your vendor/plugins directory from http://github.com/wvanbergen/scoped_search
Add the gem to your railsenvironment.rb:config.gem 'wvanbergen-scoped_search', :lib => 'scoped_search', :source => 'http://gems.github.com'
Call
rake gems:installafterwards to ensure the gem is installed.- Define in what fields your model should be searched by calling
searchable_on :some, :field, :names - Find your records by calling
search_for("query keywords")
That’s all! A short example:
class Project < ActiveRecord::Base searchable_on :name, :description end Project.search_for("search keywords").each do |project| puts project.name end # SELECT * FROM projects WHERE # (name LIKE '%search%' OR description LIKE '%search%') # AND (name LIKE '%keywords%' OR description LIKE '%keywords%')
This functionality is completely build upon named_scope. The search_for method is actually a named scope that was created by the call to searchable_on. Because these scopes can be chained, this offers some great possibilities.
For example, in Floorplanner, we only want you to search on the projects you have access to. We have implemented this access logic in another named scope. The calls can simply be chained:
class Project < ActiveRecord::Base searchable_on :name, :description named_scope :accessible_by, lambda { |user| ... } named_scope :published, :conditions => 'published_at IS NOT NULL' end @projects = Project.accessible_by(current_user).published.search_for('query') @projects.each { |project| ... }
This plugin is released under the MIT license, so please use it for any purpose you see fit. There are some TODOs: you currently can not search on fields in other tables, and splitting the search string into keywords is very basic. Please contact me if you have implemented any of these features and you are willing to share them! Do not hesitate to contact me in case or problems either.
Update: I added support for quotes and the minus sign to the query language:
Project.search_for('willem -"van bergen"').count
Update #2: Wes Hays implemented the OR keyword:
Project.search_for('wes OR hays').count.
A big thanks to Wes for helping out on this project!!
Tags: ActiveRecord, named_scope, rails, scoped_search, searching



September 21st, 2008 at 1:50 pm
Great plugin! The implementation as a named_scope makes it super easy to use.
Do you have any information on how it scales? i.e. How long does it take to Project.seach_for(params[:q]) when there are thousands or even millions of projects?
September 21st, 2008 at 2:22 pm
I haven’t done any significant testing on performance. Having said that, its performance is acceptable when using it for searching the significant list of Floorplanner projects. If you’re using MySQL, you may want to add a fulltext index on the fields you are searching to improve performance.
However, this plugin is meant to provide basic search functionality to your application. If search is really important for your site and it contains a lot of data, a fulltext search engine might be more appropriate. There are several fulltext search plugins available that offer better performance and better results, but are far more difficult to set up and maintain.
My advise: use this plugin to quickly add search functionality. Change to a fulltext search engine once you need the extra performance.
October 11th, 2008 at 9:46 pm
I add
config.gem ‘wvanbergen-scoped_search’, :lib => ’scoped_search’,
:source => ‘http://gems.github.com’
to my environment
and then
sudo rake gems:install –trace
* Invoke gems:install (first_time)
** Invoke gems:base (first_time)
** Execute gems:base
** Invoke environment (first_time)
** Execute environment
rake aborted!
wrong number of arguments (2 for 1)
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/locator.rb:92:in `add’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/locator.rb:92:in `plugins’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:63:in `locate_plugins’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:62:in `map’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:62:in `locate_plugins’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:27:in `all_plugins’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:22:in `plugins’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/rails/plugin/loader.rb:45:in `add_plugin_load_paths’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/initializer.rb:239:in `add_plugin_load_paths’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/initializer.rb:120:in `process’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/initializer.rb:97:in `send’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/initializer.rb:97:in `run’
/config/environment.rb:13
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require’
/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/dependencies.rb:510:in `require’
/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/dependencies.rb:355:in `new_constants_in’
/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/dependencies.rb:510:in `require’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/tasks/misc.rake:3
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `call’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `execute’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `each’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `execute’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:582:in `invoke_with_call_chain’
/usr/lib/ruby/1.8/monitor.rb:242:in `synchronize’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_chain’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:568:in `invoke’
/usr/lib/ruby/gems/1.8/gems/rails-2.1.1/lib/tasks/gems.rake:15
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `call’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `execute’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `each’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `execute’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:582:in `invoke_with_call_chain’
/usr/lib/ruby/1.8/monitor.rb:242:in `synchronize’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_chain’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:592:in `invoke_prerequisites’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `each’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `invoke_prerequisites’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:581:in `invoke_with_call_chain’
/usr/lib/ruby/1.8/monitor.rb:242:in `synchronize’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_chain’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:568:in `invoke’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2031:in `invoke_task’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `each’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exception_handling’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2003:in `top_level’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1982:in `run’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exception_handling’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1979:in `run’
/usr/lib/ruby/gems/1.8/gems/rake-0.8.2/bin/rake:31
/usr/bin/rake:19:in `load’
/usr/bin/rake:19
October 11th, 2008 at 11:28 pm
I believe I figured out what the problem is. You only have gem version 6.0 registered at github. I can use it by including :version => 0.6.0 in the environment config_gem command but that gives other errors.
October 16th, 2008 at 12:08 pm
Sorry for replying so late. Are you still experiencing problems with scoped search? You could add
:version => '>= 0.6.0'to your config.gem line.November 24th, 2008 at 5:13 pm
I have some issues with Rails 2.2.2 and scoped_search 0.7.2, everything works just fine while running the application.
The problem lies in migrating the production environment.
My project model has searchable_on :customer and it is the second table to be created by the migration scripts.
The error appears when running RAILS_ENV=production rake db:migrate
rake aborted!
Could not find table ‘projects’
Should I put searchable_on somewhere else so that it isn’t used during migrations?
Thanks for a great piece of code anyways, I just hope to be able to fix my issues.
November 24th, 2008 at 6:36 pm
Solved the problem by checking self.table_exists?
(Forked the project and sent a pull request)
Do you guys think that this is a sufficient solution?
November 25th, 2008 at 10:55 am
Thanks for solving this issue. I have incorporated your changes and released scoped_search 0.7.3.
Thanks for helping out!
December 26th, 2008 at 10:20 pm
[...] Fonte: Easy search with ActiveRecord [...]