simple_search 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -1
- data/VERSION +1 -1
- data/lib/simple_search/search.rb +82 -3
- data/simple_search.gemspec +1 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -57,7 +57,9 @@ Then in your view:
|
|
57
57
|
Remember, searches are idempotent so to appease the HTTP gods (and make it easy to bookmark
|
58
58
|
search results) they should be executed with GET.
|
59
59
|
|
60
|
-
That should get you started, for now.
|
60
|
+
That should get you started, for now. Read up on SimpleSearch::Search for more details, and keep in
|
61
|
+
mind that this gem was extracted from code designed to serve a specific purpose -- it has not spent
|
62
|
+
much time in the wild, so you may (will) find bugs. Please let me know about them.
|
61
63
|
|
62
64
|
== Copyright
|
63
65
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/simple_search/search.rb
CHANGED
@@ -1,7 +1,78 @@
|
|
1
1
|
module SimpleSearch
|
2
|
+
# == How it works
|
3
|
+
#
|
4
|
+
# Okay, so +form_for+ is a really handy helper, right? Yes. But it expects that whatever
|
5
|
+
# object you are building a form... er, for, responds to methods that match the name of
|
6
|
+
# the first parameter. So, for instance ...
|
7
|
+
#
|
8
|
+
# f.text_field :headly_von_headdington
|
9
|
+
#
|
10
|
+
# ... expects that the object you passed to form_for responds to the +headly_von_headdington+
|
11
|
+
# method. SimpleSearch uses this to its advantage by auto-creating methods that will
|
12
|
+
# help it build a set of conditions to search on.
|
13
|
+
#
|
14
|
+
# So, when you instantiate an object of class SimpleSearch::Search, it takes a look at the
|
15
|
+
# model you want it to search, and goes about creating a bunch of methods you will find
|
16
|
+
# handy to have available in your form_for block, based on the persistent attributes of your
|
17
|
+
# model -- that is, the columns in the database table.
|
18
|
+
#
|
19
|
+
# The methods vary by the type of data to be searched. For example purposes, let's assume
|
20
|
+
# the attribute is question is named "gipe", and see what kinds of conditions SimpleSearch
|
21
|
+
# will create depending on its data type.
|
22
|
+
#
|
23
|
+
# == Strings
|
24
|
+
#
|
25
|
+
# * +gipe+ - Matches if the searched attribute contains this string. In SQL terms, this is a
|
26
|
+
# fragment that looks like <tt>gipe LIKE '%value%'</tt>
|
27
|
+
# * +gipe_starts_with+ - Matches if the attribute starts with this string. SQL:
|
28
|
+
# <tt>gipe LIKE 'value%'</tt>
|
29
|
+
# * +gipe_exact+ - Exact match. In SQL terms: <tt>gipe = 'value'</tt>
|
30
|
+
# * +gipe_not+, +gipe_not_starts_with+, +gipe_not_exact+ - Negation of the previous examples.
|
31
|
+
# Matches if the attribute doesn't contain, start with, or equal the value, respectively.
|
32
|
+
#
|
33
|
+
# == Numbers
|
34
|
+
#
|
35
|
+
# * +gipe+ - Matches if the searched attribute equals the supplied numeric value.
|
36
|
+
# * +gipe_not+ - Matches if the searched attribute doesn't equal the value.
|
37
|
+
# * +gipe_min+ - Matches if the searched attribute is greater than or equal to the value.
|
38
|
+
# * +gipe_max+ - Matches if the searched attribute is less than or equal to the value.
|
39
|
+
#
|
40
|
+
# == Dates/DateTimes
|
41
|
+
#
|
42
|
+
# * +gipe+ - Supplied value is can be a String, Date or DateTime. This method will always search on
|
43
|
+
# a range against a datetime column.
|
44
|
+
#
|
45
|
+
# If a string, it will be parsed to a Date or DateTime, depending on the type of column it is
|
46
|
+
# being compared against, and converted to a range from beginning_of_day to end_of_day in the
|
47
|
+
# current time zone, if a range is needed. If it contains the text " to " it will be treated
|
48
|
+
# as a specific date range. So "12/25/2009 to 12/31/2009" will return results from midnight on
|
49
|
+
# Christmas day to just before the ball drops at Times Square.
|
50
|
+
# * +gipe_from+, +gipe_to+ - Sets the start or endpoint of a date/time range explicitly, much
|
51
|
+
# as min/max do on numeric values. Keep in mind that range specifications are still locked to
|
52
|
+
# a day boundary, so +gipe_from+ will be beginning_of_day and +gipe_to+ will be end_of_day when
|
53
|
+
# searching against datetime columns.
|
54
|
+
#
|
55
|
+
# == Associations
|
56
|
+
#
|
57
|
+
# When you pass a list of associations to SimpleSearch::Search#new (in the +:search_associations+
|
58
|
+
# option) SimpleSearch will add methods for that association as well. These work as you might expect,
|
59
|
+
# so a <tt>:search_association => [:manufacturer, :owner, :users]</tt> on a model that +belongs_to+ a
|
60
|
+
# manufacturer and owner, and +has_many+ users will gain methods like users_first_name_starts_with and
|
61
|
+
# manufacturer_years_in_operation_min, depending on the attributes of the associated models.
|
2
62
|
class Search
|
3
63
|
attr_reader :options, :associations
|
4
|
-
|
64
|
+
|
65
|
+
# SimpleSearch always needs a +model+ parameter to know which ActiveRecord model
|
66
|
+
# it will be wrapping around and squeezing juicy attribute goodness from.
|
67
|
+
# +options+ are, oddly enough, optional. That being said, without at least a few
|
68
|
+
# search criteria specified, SimpleSearch isn't going to be doing much besides
|
69
|
+
# providing a poorly-optimized alternative to Model.all in its +search+ method.
|
70
|
+
#
|
71
|
+
# One special option is the <tt>:search_associations</tt> option. This is a list
|
72
|
+
# of one or more associations on the model (as referenced by +has_many+, +belongs_to+,
|
73
|
+
# etc) that you would like to autogenerate search methods for, as well.
|
74
|
+
#
|
75
|
+
# Wait, what? Scroll up and read "How it works" for more details.
|
5
76
|
def initialize(model, options = {})
|
6
77
|
@model = model
|
7
78
|
@associations = [*options.delete(:search_associations)].compact
|
@@ -14,6 +85,9 @@ module SimpleSearch
|
|
14
85
|
@options = options.reject{|k, v| !respond_to?(k)}.merge dates
|
15
86
|
end
|
16
87
|
|
88
|
+
# Returns the array of conditions that is passed to ActiveRecord's find or paginate
|
89
|
+
# method by this search. Useful for debugging or to do your own custom searches without
|
90
|
+
# using the +search+ or +count+ methods.
|
17
91
|
def conditions
|
18
92
|
conditions = []
|
19
93
|
parameters = []
|
@@ -35,6 +109,10 @@ module SimpleSearch
|
|
35
109
|
conditions.blank? ? [] : [conditions.join(" AND "), *parameters]
|
36
110
|
end
|
37
111
|
|
112
|
+
# Runs the current search against the database, returning all results, or paginated
|
113
|
+
# results, depending on whether a +:page+ parameter has been received (and, of course,
|
114
|
+
# whether your model responds to paginate). All other options are passed through to the
|
115
|
+
# paginate/find call.
|
38
116
|
def search(args = {})
|
39
117
|
args.merge!(
|
40
118
|
:conditions => self.conditions,
|
@@ -47,6 +125,8 @@ module SimpleSearch
|
|
47
125
|
end
|
48
126
|
end
|
49
127
|
|
128
|
+
# Get the count of records matched by the current search. All arguments are passed to
|
129
|
+
# ActiveRecord's count method.
|
50
130
|
def count(args = {})
|
51
131
|
args.merge!(
|
52
132
|
:conditions => self.conditions,
|
@@ -217,7 +297,6 @@ module SimpleSearch
|
|
217
297
|
date_str = options[meth]
|
218
298
|
return nil if date_str.blank?
|
219
299
|
from, to = date_str.split(/\s+to\s+/)
|
220
|
-
Rails.logger.info "from = #{from}, to = #{to}"
|
221
300
|
to ||= from
|
222
301
|
from = cast_to_date_or_time(model, n, from, :from).to_s(:db) rescue nil
|
223
302
|
to = cast_to_date_or_time(model, n, to, :to).to_s(:db) rescue nil
|
@@ -275,7 +354,7 @@ module SimpleSearch
|
|
275
354
|
if endpoint == :to
|
276
355
|
date_or_time = date_or_time.end_of_day.in_time_zone
|
277
356
|
else
|
278
|
-
date_or_time.beginning_of_day.in_time_zone
|
357
|
+
date_or_time = date_or_time.beginning_of_day.in_time_zone
|
279
358
|
end
|
280
359
|
end
|
281
360
|
date_or_time
|
data/simple_search.gemspec
CHANGED