Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 134 lines (87 sloc) 6.001 kB
a9cbc43 @binarylogic Add v2 files
authored
1 = Searchlogic
2
3 <b>Searchlogic has been <em>completely</em> rewritten for v2. It is much simpler and has taken an entirely new approach. To give you an idea, v1 had ~2300 lines of code, v2 has ~350 lines of code.</b>
4
5 Searchlogic is a library that leverages named scopes to make searching in your application simple.
6
7db0934 @binarylogic Some readme cleanup
authored
7 == Search using conditions on columns
8
a9cbc43 @binarylogic Add v2 files
authored
9 Instead of explaining what Searchlogic can do, let me show you. Let's start at the top:
10
11 # We have the following model
12 User(id: integer, created_at: datetime, username: string, age: integer)
13
14 # Searchlogic gives you a bunch of named scopes for free:
15 User.username_equals("bjohnson")
16 User.username_does_not_equal("bjohnson")
17 User.username_begins_with("bjohnson")
18 User.username_like("bjohnson")
19 User.username_ends_with("bjohnson")
20 User.age_greater_than(20)
21 User.age_greater_than_or_equal_to(20)
22 User.age_less_than(20)
23 User.age_less_than_or_equal_to(20)
24 User.username_null
25 User.username_blank
26
27 # You can also order by columns
28 User.ascend_by_username
29 User.descend_by_username
30 User.order("ascend_by_username")
31
32 Keep in mind, these are just named scopes, you can chain them, call methods off of them, etc:
33
34 scope = User.username_like("bjohnson").age_greater_than(20).ascend_by_username
35 scope.all
36 scope.first
37 scope.count
38 # etc...
39
7db0934 @binarylogic Some readme cleanup
authored
40 == Search using conditions on association columns
a9cbc43 @binarylogic Add v2 files
authored
41
42 You also get named scopes for any of your associations:
43
44 # We have the following relationships
45 User.has_many :orders
46 Order.has_many :line_items
47 LineItem
48
49 # Set conditions on association columns
50 User.orders_total_greater_than(20)
51 User.orders_line_items_price_greater_than(20)
52
53 # Order by association columns
54 User.ascend_by_order_total
55 User.descend_by_orders_line_items_price
56
57 Again these are just named scopes. You can chain them together, call methods off of them, etc. What's great about these named scopes is that they do NOT use the :include option, making them much faster. Instead they create a LEFT OUTER JOIN and pass it to the :joins option, which is great for performance. If you want to use the :include option, just specify it:
58
59 User.orders_line_items_price_greater_than(20).all(:include => {:orders => :line_items})
60
61 Now all of Searchlogic's goodness fits nicely into your app and you can use it with your custom named scopes. Nice and clean.
62
63 == Make searching in your application trivial
64
65 The above is great, but what about tying all of this in with a search form in your application? Just do this...
66
67 User.search(:username_like => "bjohnson", :age_less_than => 20)
68
69 The above is equivalent to:
70
71 User.username_like("bjohnson").age_less_than(20)
72
73 All that the search method does is chain named scopes together for you. What's so great about that? It keeps your controllers extremely simple:
74
75 class UsersController < ApplicationController
76 def index
77 @search = User.search(params[:search])
78 @users = @search.all
79 end
80 end
81
82 It doesn't get any simpler than that. Adding a search condition is as simple as adding a condition to your form. Remember all of those named scopes above? Just create fields with the same names:
83
84 - form_for @search do |f|
85 = f.text_field :username_like
86 = f.select :age_greater_than, (0..100)
87 = f.text_field :orders_total_greater_than
88 = f.submit
89
90 == Use your existing named scopes
91
92 This is one of the big differences between Searchlogic v1 and v2. What about your existing named scopes? Let's say you have this:
93
94 User.named_scope :four_year_olds, :conditions => {:age => 4}
95
96 Again, these are all just named scopes, use it in the same way:
97
98 User.search(:four_year_olds => true, :username_like => "bjohnson")
99
100 Notice we pass true as the value. If a named scope does not accept any parameters (arity == 0) you can simply pass it true or false. If you pass false, the named scope will be ignored. If your named scope accepts a parameter, the value will be passed right to the named scope regardless of the value.
101
102 Now just throw it in your form:
103
104 - form_for @search do |f|
105 = f.text_field :username_like
106 = f.check_box :four_year_olds
107 = f.submit
108
109 What's great about this is that you can do just about anything you want. If Searchlogic doesn't provide a named scope for that crazy searching edge case that you need, just create your own named scope. The sky is the limit.
110
111 == Pagination (leverage will_paginate)
112
113 Instead of recreating the wheel with pagination, Searchlogic works great with will_paginate. All that Searchlogic is doing is creating named scopes, and will_paginate works great with named scopes:
114
115 User.username_like("bjohnson").age_less_than(20).paginate(:page => params[:page])
7db0934 @binarylogic Some readme cleanup
authored
116 User.search(:username_like => "bjohnson", :age_less_than => 20).paginate(:page => params[:page])
a9cbc43 @binarylogic Add v2 files
authored
117
118 If you don't like will_paginate, use another solution, or roll your own. Pagination really has nothing to do with searching, and the main goal for Searchlogic v2 was to keep it lean and simple. No reason to recreate the wheel and bloat the library.
119
120 == Under the hood
121
122 Before I use a library in my application I like to glance at the source and try to at least understand the basics of how it works. If you are like me, a nice little explanation from the author is always helpful:
123
124 Searchlogic utilizes method_missing to create all of these named scopes. When it hits method_missing it creates a named scope to ensure it will never hit method missing for that named scope again. Sort of a caching mechanism. It works in the same fashion as ActiveRecord's "find_by_*" methods. This way only the named scopes you need are created and nothing more.
125
126 That's about it, the named scope options are pretty bare bones and created just like you would manually.
127
d8f61c4 @binarylogic Update readme
authored
128 == Credit
129
7db0934 @binarylogic Some readme cleanup
authored
130 Thanks a lot to {Tyler Hunt}[http://github.com/tylerhunt] for helping plan, design, and start the project. He was a big help.
d8f61c4 @binarylogic Update readme
authored
131
a9cbc43 @binarylogic Add v2 files
authored
132 == Copyright
133
134 Copyright (c) 2009 {Ben Johnson of Binary Logic}[http://www.binarylogic.com], released under the MIT license
Something went wrong with that request. Please try again.