#176
Aug 24, 2009

Searchlogic

Searchlogic makes searching models easier than ever with its assortment of named scopes. In this episode I show you how to create simple and advanced searches.
Download (23.9 MB, 13:51)
alternative download for iPod & Apple TV (17 MB, 13:51)

Resources

sudo gem install searchlogic
# config/environment.rb
config.gem "searchlogic"

# script/console
ActiveRecord::Base.logger = Logger.new(STDOUT)
Product.name_like("Video")
Product.name_not_like("Video").price_gt(5).price_lt(200)
Product.name_like_any(["couch", "table"])
Product.name_like_all(["video", "console"])
Product.category_name_like("elect")
Product.search(:category_name_like => "elect", :price_lt => "100")
s = _
s.all
s.name_like("video")
Product.ascend_by_name

# products_controller.rb
@products = Product.name_like_all(params[:search].to_s.split).ascend_by_name
# or
@search = Product.search(params[:search])
@products = @search.all
<!-- index.html.erb -->
<% form_for @search do |f| %>
  <p>
    <%= f.label :name_like, "Name" %><br />
    <%= f.text_field :name_like %>
  </p>
  <p>
    <%= f.label :category_id_equals, "Category" %><br />
    <%= f.collection_select :category_id_equals, Category.all, :id, :name, :include_blank => true %>
  </p>
  <p>
    <%= f.label :price_gte, "Price Range" %><br />
    <%= f.text_field :price_gte, :size => 8 %> - <%= f.text_field :price_lte, :size => 8 %>
  </p>
  <p>
    <%= f.submit "Submit" %>
  </p>
<% end %>

<p>
  Sort by:
  <%= order @search, :by => :name %> |
  <%= order @search, :by => :price %>
</p>

RSS Feed for Episode Comments 59 comments

1. Freddy Andersen Aug 24, 2009 at 01:12

I just started using Searchlogic a few weeks back and am loving it. Great to see a cast about this great tool and learn some new tricks..

Nice work!


2. CodeOfficer Aug 24, 2009 at 01:18

Another great cast Ryan. Thanks.

One small bug I found. At 13:00 you call it Authlogic, instead of Searchlogic. Its probably too late to fix that but I thought I'd mention it :)


3. Roy van der Meij Aug 24, 2009 at 01:51

Great episode! But I have one question.

How come form_for @search get's mapped to the index action of ProductsController, where is that route configured?


4. Ben Johnson Aug 24, 2009 at 02:31

Great job Ryan, this is a great video. You did an excellent job. It definitely beats my boring tutorials.

Keep up the good work.


5. Brian Armstrong Aug 24, 2009 at 06:08

Simply beautiful plugin!

Just wanted to mention, the long messy URL's don't bother me from a UI point of view, if for no other reason than the fact Google does it and people are used to it. I don't think you'll freak out any users with a long URL.

Great video though, thanks Ryan!


6. Alexander Kahn Aug 24, 2009 at 07:25

Hi Ryan,

Thanks for this screencast -- this would have saved me a lot of time last week! ;) I feel like the safety/security issues of using this method for a public search feature could be averted if before using the search method, you slice the params hash to only include the parameters that were expected from the form. Then any other parameters wouldn't be acted upon. What do you think of that?

Also, do named scopes (as well as authlogic) automatically escape values, removing the need to call h() manually?

Cheers,
Alex


7. EppO Aug 24, 2009 at 07:30

@Roy van der Meij

I don't think you have to put a route. @search is an array of products stored in the index action of Products controller, so it should do the trick with form_for.


8. Alexander Kahn Aug 24, 2009 at 07:34

Ahem, I mean searchlogic in the comment above.


9. vinnyt Aug 24, 2009 at 07:47

Ryan,
great episode, as always. In any event I am stuck on the hirb stuff, I tried rtfm on the hirb page but it doesn't work can you give me a quick pointer on this one?


10. Tevez Aug 24, 2009 at 08:14

Hi Ryan,

I have a question, in the collection_select if users select blank, will it means select :all or select blank? I hope it's the former one, I'll try it out later.


11. Chris Aug 24, 2009 at 09:51

Nice! Still playing around with it...getting inconsistent results. Maybe my rails version(2.2.2)?

Also, how does one "preload" commands like the ActiveRecord::Base::logger = Logger.new(STDOUT) or a require "<blah>" so they are available as soon as you start the console?


12. cldwalker Aug 24, 2009 at 10:31

@vinnyt For hirb documentation see http://tagaholic.me/hirb/doc and http://github.com/cldwalker/hirb/tree/master#readme .


13. BasicObject Aug 24, 2009 at 11:05

How do I implement searching multiple columns? Say I have an address book database and I want one search field to query the name column, the address column and the email column. How might this be accomplished using searchlogic and a single search field?


14. Vann Aug 24, 2009 at 11:27

@BasicObject I ran into the same problem with SearchLogic and decided to extend my own ar_helper plugin to do just that, take a look at the #search method here at: http://github.com/vanntastic/ar_helper/tree/master. In your example above, you can do this instead:

<script src="http://gist.github.com/174016.js"></script>


15. jDeppen Aug 24, 2009 at 12:11

I'm trying to use Searchlogic and allow users to save searches for my real estate website. I'm trying to make it a ListingSearch resource.

It seemed like Ryan was suggesting using Searchlogic for only admin purposes. Should I roll my own "old school" search?

Anyone have any thoughts?


16. Brad Aug 24, 2009 at 13:06

@chris make an .irbrc file in your home folder and put this in the file

http://gist.github.com/174133

enjoy.


17. Oleg Aug 24, 2009 at 13:41

While this searchlogic is great, it's pretty outdated. You should not use 'searchlogic' gem. Instead grab the 'binarylogic-searchlogic'. See: http://www.binarylogic.com/2009/06/15/searchlogic-v2-officially-released/

Basically it's a complete rewrite that deals with searches quite differently and way cleaner.


18. Oleg Aug 24, 2009 at 13:43

Actually it seems that they are identical now. Silly me.


19. Carl Aug 24, 2009 at 15:57

Great screencast. Worth it just for the tip about irb and assigning variable with an underscore!


20. Kieran P Aug 24, 2009 at 18:16

Packed full of win! The underscore in IRB hint alone was well worth the download, but being able to get rid of several lines of complex code using searchlogic.... excellent episode. Keep it up.


21. Michael Voigt Aug 25, 2009 at 04:43

Nice, but the better way is to use ThinkingSphinx with sphinx_scope.


22. Yuval Aug 26, 2009 at 12:52

Is there any way to get the logger to run automatically when script/console is started up? I can't imagine not wanting it active. Cheers.


23. Ash McKenzie Aug 26, 2009 at 18:14

One thing I noticed when using searchlogic is the class of the return value is not what you expect: -

1. User.find_by_login('bob').class -> returns User

2. User.login_equals('bob').class -> returns ActiveRecord::NamedScope::Scope

This is an important distinction as you cannot call methods such as .destroy on the second example.


24. Tim Gossett Aug 27, 2009 at 12:11

@jDeppen: go ahead and use SearchLogic for the front-end search, but make sure the controller scrubs out any values in the search hash that you don't want there.

http://gist.github.com/176481

This way, you can even define defaults for the search.


25. Tim Gossett Aug 27, 2009 at 12:22

Thanks, Ryan! Great episode.

I was surprised that there was no mention SearchLogic's interoperability with will_paginate. Paginating search seems to be one of the big hurdles newbie Rails developers tackle.

All one needs to do is call the paginate method on the search, thus:

@search = Product.search(params[:search])
@products = @search.paginate( :page => params[:page] )


26. Pablo Gonzalez Aug 28, 2009 at 09:18

Excellent episode! It only shows you always get better and better.

By the way, I love the programming style you use.


27. Terence Aug 28, 2009 at 11:52

I want this locally on my machine.
Product.name_not_like("Video").price_gt(5).price_lt(200)

Produces

SELECT * FROM `products` WHERE (products.price < 200)


28. hartwig Aug 30, 2009 at 12:57

Hi Ryan!
Great Screencast. I use Searchlogic in my hobby project. But currently I have a little problem with Searchlogic.

For example:
 1: User.login_or_email_like("foobar")
 2: User.search(:login_or_email_like => "foobar")

Correct me if I am wrong but these two should have the same result.
The former one works fine, but the latter one does not it returns all Users.

Currently I read something about cells (http://cells.rubyforge.org/b) in RailsWay. Did you know cells?

Hear you tomorrow


29. eric Sep 01, 2009 at 10:43

@hartwig,

I have the same issue. Any ideas anyone? Maybe we're looking at a gem conflict?


30. Milan Jaric Sep 01, 2009 at 13:34

Simply THE BEST :)


31. hartwig Sep 01, 2009 at 15:47

I looked at the code and i believe that the method which is responsible for processing the "or" conditions, don't get called if you use the User.search ... form.

But I am not sure.

I am still learning the "meta-programming" thing in ruby. But I believe Dave Thomas or Paolo Perrotta sad there is no such thing, its just programming ;-)

I don't have a github account yet, but can somebody post there a comment about the searchlogic issue.

@ryan Your videos are great. They help me to forget php ;-)


32. Willem van Bergen Sep 02, 2009 at 09:35

If you want to offer your users a simple search box instead of a complex form to search your models, check out scoped_search: http://github.com/wvanbergen/scoped_search

class Model < ActiveRecord::Base
  scoped_search :on =>[:name, :description, :created]
end

Model.search_for(params[:q]).paginate(...)

This will work with queries like:
- keyword1 keyword2 keyword3
- (a | b) & created > 2009-01-01
- name = "Willem van Bergen"


33. ssbothwell Sep 02, 2009 at 23:38

At the end of the video Ryan mentions the form_for method should not be used for public facing pages. He says to setup custom forms in those situations. What exactly is meant by that? Does that mean to use form_tag to build the form? If so, how do I do this using multiple scopes?


34. Marc Sep 04, 2009 at 05:05

@Tim Gossett - You need to post what you said about getting will_paginate to work with searchlogic in the forums. This is the only place I found that solution... even though it's a simple easy one some people don't think of doing that. Thanks sooo much!!


35. Aditya Sanghi Sep 08, 2009 at 01:12

Hi Ryan,

How did you get the query executed to be displayed on the console? Another irb trick? Loved the Hirb hint!

Cheers,
Aditya


36. juan Sep 13, 2009 at 10:18

Great video!... very usefull! thanks!


37. Nick Sep 17, 2009 at 03:24

@hartwig @Ryan @eric,
i have the same problem with the or-condition. i.e. User.search(:firstname_or_lastname_like => "foo") is not working. In the console i get the notice: #<Searchlogic::Search:0x34503f0 @conditions={:firstname_like_or_lastname_like=>false}, @current_scope=nil, @klass=User(id: integer, ....
Has anyone found a solution to this problem?
Great post thought, Ryan. As always.


38. pulkit Sep 22, 2009 at 04:48

Hi Ryan,

I have two text_field_tag in my view.

In the first text_field_tag, I can enter name, category or description.

In the second text_field_tag, I can enter city, state or zip.

Right now I am using form_tag.

How can I use form_for to use order in above situation?


39. Austin Ginder Sep 22, 2009 at 20:51

Is it possible to pass a SQL limit?


40. defucius Oct 02, 2009 at 10:35

Is it possible to do sorting on two columns like:

ascend_by_last_name.ascend_by_first_name?

It seems searchlogic ignores the second ordering command.


41. Fernando Kosh Oct 06, 2009 at 23:07

Thanks for this great video!
;-)


42. hgujral Oct 18, 2009 at 18:29

Does this even work with virtual attributes?

I keep getting an error "undefined method `age_greater_than' for #<Class:0x48fff80>" where age is a virtual attribute.

Anyone?


43. Alican Oct 29, 2009 at 05:27

Hi, ryan.
This screencast's link broken please check.

Thanks.


44. kyle Nov 01, 2009 at 17:18

First of all, thanks for the awesome screencast. I just came across this site recently and it's been an amazing resource so far.

But I'm having some trouble. I've been able to implement the search form on my model's index.html.erb file, but putting it in the application.html.erb file to act as a global search accessible from any page results in me getting whiny_nil errors all over the place.

My app is a listing of bars and their respective specials. So the search works great on the index page where all the bars are listed. I can search just fine, everything works as expected from that side of things.

But when I click a link to see additional details about the bar, THAT is when I get the whiny_nil.

I just don't know what to do or why it doesn't work. I can't seem to find anything online about implementing a global search using SearchLogic. :(


45. kyle Nov 01, 2009 at 18:19

Nevermind! I figured it out...global search form required a global variable. :)


46. Justin Nov 02, 2009 at 14:49

Have modifiers been removed from version 2 of Searchlogic? If not how do you use them, all I can find are old out-dated examples from version 1.x


47. Kleber Shimabuku Nov 03, 2009 at 14:37

@Austin Ginder try to use will_paginate for it. I think it's the only way for now.


48. Gordon Dec 02, 2009 at 04:21

hey, Ryan,

 Searchlogic V2 is out.
 Is this for V2? If not, could you please show one for V2?
 Would be nice to see how you go abouts setting up routing for the search resource :) thanks


49. Peter Dec 05, 2009 at 08:49

I've been able to implement the search form on my model's index.html.erb file


50. Gordon Dec 16, 2009 at 04:22

hi ryan
 great post. I managed to get searchlogic 2.3 working for me. When I use will_paginate, the only thing that breaks is the "order".
When i load my search results page, i seem to get an error indicating "order" is not defined.

I later found out that to get ordering to work again, i need to be able to generate the same url (with params) and append the order clause to it.

1) how do i do it?
2) with searchlogic 2.3.+ and will_paginate, how can we still maintain using "order" in the view as per your tute?


51. Ritesh Dec 16, 2009 at 08:22

thnaks for this great video.

I am facing a problem with will_paginate, if i want to use pagination along with <%= order %>, it is not working and giving me this error

undefined method `order' for #<WillPaginate::Collection:0xb6f1fa5c>
Thanks


52. yeni müzik Dec 29, 2009 at 15:51

very useful screencast. thanks.


53. flunder Jan 06, 2010 at 10:10

Great Railscast as usual! Digging a bit further, i found using named scopes essential...


54. Gordon Jan 12, 2010 at 01:19

hi there,
 
 Like Ritesh who posted on Dec 16, 2009 at 08:22 ,
I am also facing a problem with the undefined method "order".

 Please help, Ryan?


55. freerealmscoins Jan 12, 2010 at 16:41

It is very good.I like to see it.I will try it.Thank you .Have a good time.


56. wholesale nike shoes Jan 13, 2010 at 21:51

I later found out that to get ordering to work again


57. mike Jan 14, 2010 at 09:31

I get a runtime error when i try to access the search form page. I can search fine in the script/console but when i got to my search page i get " Showing app/views/groups/search.html.erb where line #1 raised:

Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id"

I cant figure out what is causing this problem


58. Mike Jan 14, 2010 at 09:41

I tried # OR part in the controller and now i get "wrong number of arguments (1 for 2)"

I dont get what i keep doing wrong


59. javon Jan 25, 2010 at 22:25

I dont get what i keep doing wrong

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source