searchgasm 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +8 -0
- data/Manifest +2 -4
- data/README.rdoc +3 -4
- data/lib/searchgasm/active_record/base.rb +23 -20
- data/lib/searchgasm/condition/base.rb +18 -7
- data/lib/searchgasm/condition/does_not_equal.rb +2 -4
- data/lib/searchgasm/condition/equals.rb +2 -4
- data/lib/searchgasm/condition/is_blank.rb +23 -0
- data/lib/searchgasm/condition/is_nil.rb +23 -0
- data/lib/searchgasm/conditions/base.rb +9 -9
- data/lib/searchgasm/config.rb +14 -14
- data/lib/searchgasm/helpers/control_types/link.rb +55 -0
- data/lib/searchgasm/helpers/control_types/links.rb +4 -9
- data/lib/searchgasm/helpers/control_types/select.rb +7 -4
- data/lib/searchgasm/helpers/form.rb +2 -2
- data/lib/searchgasm/helpers/utilities.rb +3 -2
- data/lib/searchgasm/search/base.rb +20 -2
- data/lib/searchgasm/search/conditions.rb +4 -14
- data/lib/searchgasm/search/ordering.rb +30 -29
- data/lib/searchgasm/search/pagination.rb +16 -10
- data/lib/searchgasm/shared/searching.rb +21 -19
- data/lib/searchgasm/shared/utilities.rb +18 -0
- data/lib/searchgasm/version.rb +1 -1
- data/lib/searchgasm.rb +3 -1
- data/searchgasm.gemspec +7 -11
- data/test/test_active_record_associations.rb +2 -2
- data/test/test_condition_base.rb +2 -2
- data/test/test_condition_types.rb +48 -0
- data/test/test_conditions_base.rb +5 -5
- data/test/test_search_base.rb +8 -8
- metadata +6 -10
- data/lib/searchgasm/active_record.rb +0 -8
- data/lib/searchgasm/helpers/control_types.rb +0 -57
- data/lib/searchgasm/helpers.rb +0 -9
- data/lib/searchgasm/search.rb +0 -7
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 1.1.2 released 2008-09-22
|
2
|
+
|
3
|
+
* Fixed bug with select control types not using :search_obj to determine its select values.
|
4
|
+
* Added is_nil and is_blank condition types.
|
5
|
+
* "memoized" various attributes for performance enhancements
|
6
|
+
* Removed the :order option from calculation options when :order is useless and just slows down query.
|
7
|
+
* Switched from using :include to :joins, big performance increase
|
8
|
+
|
1
9
|
== 1.1.1 released 2008-09-19
|
2
10
|
|
3
11
|
* Fixed typo in "next page" button.
|
data/Manifest
CHANGED
@@ -3,7 +3,6 @@ examples/README.rdoc
|
|
3
3
|
init.rb
|
4
4
|
lib/searchgasm/active_record/associations.rb
|
5
5
|
lib/searchgasm/active_record/base.rb
|
6
|
-
lib/searchgasm/active_record.rb
|
7
6
|
lib/searchgasm/condition/base.rb
|
8
7
|
lib/searchgasm/condition/begins_with.rb
|
9
8
|
lib/searchgasm/condition/child_of.rb
|
@@ -15,6 +14,8 @@ lib/searchgasm/condition/equals.rb
|
|
15
14
|
lib/searchgasm/condition/greater_than.rb
|
16
15
|
lib/searchgasm/condition/greater_than_or_equal_to.rb
|
17
16
|
lib/searchgasm/condition/inclusive_descendant_of.rb
|
17
|
+
lib/searchgasm/condition/is_blank.rb
|
18
|
+
lib/searchgasm/condition/is_nil.rb
|
18
19
|
lib/searchgasm/condition/keywords.rb
|
19
20
|
lib/searchgasm/condition/less_than.rb
|
20
21
|
lib/searchgasm/condition/less_than_or_equal_to.rb
|
@@ -30,16 +31,13 @@ lib/searchgasm/helpers/control_types/remote_link.rb
|
|
30
31
|
lib/searchgasm/helpers/control_types/remote_links.rb
|
31
32
|
lib/searchgasm/helpers/control_types/remote_select.rb
|
32
33
|
lib/searchgasm/helpers/control_types/select.rb
|
33
|
-
lib/searchgasm/helpers/control_types.rb
|
34
34
|
lib/searchgasm/helpers/form.rb
|
35
35
|
lib/searchgasm/helpers/utilities.rb
|
36
|
-
lib/searchgasm/helpers.rb
|
37
36
|
lib/searchgasm/search/base.rb
|
38
37
|
lib/searchgasm/search/conditions.rb
|
39
38
|
lib/searchgasm/search/ordering.rb
|
40
39
|
lib/searchgasm/search/pagination.rb
|
41
40
|
lib/searchgasm/search/protection.rb
|
42
|
-
lib/searchgasm/search.rb
|
43
41
|
lib/searchgasm/shared/searching.rb
|
44
42
|
lib/searchgasm/shared/utilities.rb
|
45
43
|
lib/searchgasm/shared/virtual_classes.rb
|
data/README.rdoc
CHANGED
@@ -9,6 +9,7 @@ Searchgasm is orgasmic. Maybe not orgasmic, but you will get aroused. So go grab
|
|
9
9
|
* <b>Documentation:</b> http://searchgasm.rubyforge.org
|
10
10
|
* <b>Easy pagination, ordering, and searching tutorial:</b> http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchgasm
|
11
11
|
* <b>Live example of the tutorial above (with source):</b> http://searchgasm_example.binarylogic.com
|
12
|
+
* <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/16601-searchgasm
|
12
13
|
|
13
14
|
== Install and use
|
14
15
|
|
@@ -288,6 +289,8 @@ Some of these conditions come with aliases, so you have your choice how to call
|
|
288
289
|
|
289
290
|
:equals => :is
|
290
291
|
:does_not_equal => :is_not, :not
|
292
|
+
:is_nil => :nil, :is_null, :null
|
293
|
+
:is_blank => :blank
|
291
294
|
:begins_with => :starts_with, :sw, :bw, :start
|
292
295
|
:contains => :like, :has
|
293
296
|
:ends_with => :ew, :ends, :end
|
@@ -353,10 +356,6 @@ ActiveRecord should never know about Searchgasm
|
|
353
356
|
|
354
357
|
What that rule means is that any options you pass when searching get "sanitized" down into options ActiveRecord can understand. Searchgasm serves as a transparent filter between you and ActiveRecord. It doesn't dig into the ActiveRecord internals, it only uses what is publicly available. It jumps in and helps out <em>only</em> when needed, otherwise it sits back and stays completely out of the way. Between that and the extensive tests, this is a solid and fast plugin.
|
355
358
|
|
356
|
-
== Reporting problems / bugs
|
357
|
-
|
358
|
-
http://binarylogic.lighthouseapp.com/projects/16601-searchgasm
|
359
|
-
|
360
359
|
== Credits
|
361
360
|
|
362
361
|
Author: {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com]
|
@@ -1,4 +1,8 @@
|
|
1
1
|
module Searchgasm
|
2
|
+
# == Searchgasm ActiveRecord
|
3
|
+
#
|
4
|
+
# Hooks into ActiveRecord to add all of the searchgasm functionality into your models. Only uses what is publically available, doesn't dig into internals, and
|
5
|
+
# searchgasm only gets involved when needed.
|
2
6
|
module ActiveRecord
|
3
7
|
# = Searchgasm ActiveRecord Base
|
4
8
|
# Adds in base level functionality to ActiveRecord
|
@@ -6,7 +10,7 @@ module Searchgasm
|
|
6
10
|
# This is an alias method chain. It hook into ActiveRecord's "calculate" method and checks to see if Searchgasm should get involved.
|
7
11
|
def calculate_with_searchgasm(*args)
|
8
12
|
options = args.extract_options!
|
9
|
-
options = filter_options_with_searchgasm(options)
|
13
|
+
options = filter_options_with_searchgasm(options, false)
|
10
14
|
args << options
|
11
15
|
calculate_without_searchgasm(*args)
|
12
16
|
end
|
@@ -124,7 +128,7 @@ module Searchgasm
|
|
124
128
|
end
|
125
129
|
|
126
130
|
private
|
127
|
-
def filter_options_with_searchgasm(options = {})
|
131
|
+
def filter_options_with_searchgasm(options = {}, searching = true)
|
128
132
|
return options unless Searchgasm::Search::Base.needed?(self, options)
|
129
133
|
search = Searchgasm::Search::Base.create_virtual_class(self).new # call explicitly to avoid merging the scopes into the searcher
|
130
134
|
search.acting_as_filter = true
|
@@ -138,32 +142,31 @@ module Searchgasm
|
|
138
142
|
end
|
139
143
|
end
|
140
144
|
search.options = options
|
141
|
-
search.sanitize
|
145
|
+
search.sanitize(searching)
|
142
146
|
end
|
143
147
|
|
144
148
|
def searchgasm_conditions(options = {})
|
145
|
-
searcher =
|
146
|
-
conditions =
|
147
|
-
|
148
|
-
|
149
|
-
with_scope(:find => {:conditions => options[:conditions]}) do
|
150
|
-
searcher = Searchgasm::Conditions::Base.create_virtual_class(self).new(scope(:find)[:conditions])
|
151
|
-
searcher.conditions = conditions unless conditions.nil?
|
152
|
-
end
|
153
|
-
|
149
|
+
searcher = Searchgasm::Conditions::Base.create_virtual_class(self).new
|
150
|
+
conditions = scope(:find) && scope(:find)[:conditions]
|
151
|
+
searcher.scope = {:conditions => conditions} if conditions
|
152
|
+
searcher.conditions = options
|
154
153
|
searcher
|
155
154
|
end
|
156
155
|
|
157
156
|
def searchgasm_searcher(options = {})
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
157
|
+
scope = {}
|
158
|
+
current_scope = scope(:find) && scope(:find).deep_dup
|
159
|
+
if current_scope
|
160
|
+
[:conditions, :include, :joins].each do |option|
|
161
|
+
value = current_scope.delete(option)
|
162
|
+
next if value.blank?
|
163
|
+
scope[option] = value
|
164
|
+
end
|
165
165
|
end
|
166
|
-
|
166
|
+
searcher = Searchgasm::Search::Base.create_virtual_class(self).new
|
167
|
+
searcher.scope = scope
|
168
|
+
searcher.options = current_scope
|
169
|
+
searcher.options = options
|
167
170
|
searcher
|
168
171
|
end
|
169
172
|
end
|
@@ -9,6 +9,9 @@ module Searchgasm
|
|
9
9
|
|
10
10
|
attr_accessor :column, :klass
|
11
11
|
attr_reader :value
|
12
|
+
class_inheritable_accessor :ignore_blanks, :type_cast_value
|
13
|
+
self.ignore_blanks = true
|
14
|
+
self.type_cast_value = true
|
12
15
|
|
13
16
|
class << self
|
14
17
|
# Name of the condition inferred from the class name
|
@@ -27,6 +30,14 @@ module Searchgasm
|
|
27
30
|
[]
|
28
31
|
end
|
29
32
|
|
33
|
+
def ignore_blanks? # :nodoc:
|
34
|
+
ignore_blanks == true
|
35
|
+
end
|
36
|
+
|
37
|
+
def type_cast_value? # :nodoc:
|
38
|
+
type_cast_value == true
|
39
|
+
end
|
40
|
+
|
30
41
|
# Sane as name_for_column but for the class as a whole. For example the tree methods apply to the class as a whole and not
|
31
42
|
# specific columns. Any condition that applies to columns should probably return nil here.
|
32
43
|
def name_for_klass(klass)
|
@@ -64,11 +75,6 @@ module Searchgasm
|
|
64
75
|
@explicitly_set_value == true
|
65
76
|
end
|
66
77
|
|
67
|
-
# In most cases a blank value should be ignored, except for conditions like equals. A blank value is meaningful there, but a blank value for they keyswords condition is not.
|
68
|
-
def ignore_blanks?
|
69
|
-
true
|
70
|
-
end
|
71
|
-
|
72
78
|
# A convenience method for the name of the method for that specific column or klass
|
73
79
|
def name
|
74
80
|
column ? self.class.name_for_column(column) : self.class.name_for_klass(klass)
|
@@ -110,15 +116,20 @@ module Searchgasm
|
|
110
116
|
to_conditions(v)
|
111
117
|
end
|
112
118
|
end
|
119
|
+
|
120
|
+
# Should the value be automatically type casted
|
121
|
+
def type_cast_value?
|
122
|
+
true
|
123
|
+
end
|
113
124
|
|
114
125
|
# The value for the condition
|
115
126
|
def value
|
116
|
-
@value.is_a?(String) ? column.type_cast(@value) : @value
|
127
|
+
self.class.type_cast_value? && @value.is_a?(String) ? column.type_cast(@value) : @value
|
117
128
|
end
|
118
129
|
|
119
130
|
# Sets the value for the condition, will ignore place if ignore_blanks?
|
120
131
|
def value=(v)
|
121
|
-
return if ignore_blanks? && v.blank?
|
132
|
+
return if self.class.ignore_blanks? && v.blank?
|
122
133
|
self.explicitly_set_value = true
|
123
134
|
@value = v
|
124
135
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Condition
|
3
3
|
class DoesNotEqual < Base
|
4
|
+
self.ignore_blanks = false
|
5
|
+
|
4
6
|
class << self
|
5
7
|
def aliases_for_column(column)
|
6
8
|
["#{column.name}_is_not", "#{column.name}_not"]
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
|
-
def ignore_blanks?
|
11
|
-
false
|
12
|
-
end
|
13
|
-
|
14
12
|
def to_conditions(value)
|
15
13
|
# Delegate to equals and then change
|
16
14
|
condition = Equals.new(klass, column)
|
@@ -1,16 +1,14 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Condition
|
3
3
|
class Equals < Base
|
4
|
+
self.ignore_blanks = false
|
5
|
+
|
4
6
|
class << self
|
5
7
|
def aliases_for_column(column)
|
6
8
|
["#{column.name}", "#{column.name}_is"]
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
|
-
def ignore_blanks?
|
11
|
-
false
|
12
|
-
end
|
13
|
-
|
14
12
|
def to_conditions(value)
|
15
13
|
# Let ActiveRecord handle this
|
16
14
|
klass.send(:sanitize_sql_hash_for_conditions, {column.name => value})
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class IsBlank < Base
|
4
|
+
self.ignore_blanks = false
|
5
|
+
self.type_cast_value = false
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def aliases_for_column(column)
|
9
|
+
["#{column.name}_blank"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_conditions(value)
|
14
|
+
# Some databases handle null values differently, let AR handle this
|
15
|
+
if value == true || value == "true" || value == 1 || value == "1"
|
16
|
+
"#{quoted_table_name}.#{quoted_column_name} is NULL or #{quoted_table_name}.#{quoted_column_name} = ''"
|
17
|
+
elsif value == false || value == "false" || value == 0 || value == "0"
|
18
|
+
"#{quoted_table_name}.#{quoted_column_name} is NOT NULL and #{quoted_table_name}.#{quoted_column_name} != ''"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class IsNil < Base
|
4
|
+
self.ignore_blanks = false
|
5
|
+
self.type_cast_value = false
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def aliases_for_column(column)
|
9
|
+
["#{column.name}_nil", "#{column.name}_is_null", "#{column.name}_null"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_conditions(value)
|
14
|
+
# Some databases handle null values differently, let AR handle this
|
15
|
+
if value == true || value == "true" || value == 1 || value == "1"
|
16
|
+
"#{quoted_table_name}.#{quoted_column_name} is NULL"
|
17
|
+
elsif value == false || value == "false" || value == 0 || value == "0"
|
18
|
+
"#{quoted_table_name}.#{quoted_column_name} is NOT NULL"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -5,9 +5,9 @@ module Searchgasm
|
|
5
5
|
# Represents a collection of conditions and performs various tasks on that collection. For information on each condition see Searchgasm::Condition.
|
6
6
|
# Each condition has its own file and class and the source for each condition is pretty self explanatory.
|
7
7
|
class Base
|
8
|
-
include
|
9
|
-
include
|
10
|
-
include
|
8
|
+
include Shared::Utilities
|
9
|
+
include Shared::Searching
|
10
|
+
include Shared::VirtualClasses
|
11
11
|
|
12
12
|
attr_accessor :any, :relationship_name, :sql
|
13
13
|
|
@@ -104,15 +104,15 @@ module Searchgasm
|
|
104
104
|
@any == true || @any == "true" || @any == "1" || @any == "yes"
|
105
105
|
end
|
106
106
|
|
107
|
-
# A list of
|
108
|
-
def
|
109
|
-
|
107
|
+
# A list of joins to use when searching, includes relationships
|
108
|
+
def joins
|
109
|
+
j = []
|
110
110
|
associations.each do |association|
|
111
111
|
next if association.conditions.blank?
|
112
|
-
|
113
|
-
|
112
|
+
association_joins = association.joins
|
113
|
+
j << (association_joins.blank? ? association.relationship_name.to_sym : {association.relationship_name.to_sym => association_joins})
|
114
114
|
end
|
115
|
-
|
115
|
+
j.blank? ? nil : (j.size == 1 ? j.first : j)
|
116
116
|
end
|
117
117
|
|
118
118
|
def inspect
|
data/lib/searchgasm/config.rb
CHANGED
@@ -43,6 +43,18 @@ module Searchgasm
|
|
43
43
|
@desc_indicator = value
|
44
44
|
end
|
45
45
|
|
46
|
+
def hidden_fields # :nodoc:
|
47
|
+
@hidden_fields ||= (Search::Base::SPECIAL_FIND_OPTIONS - [:page])
|
48
|
+
end
|
49
|
+
|
50
|
+
# Which hidden fields to automatically include when creating a form with a Searchgasm object. See Searchgasm::Helpers::Form for more info.
|
51
|
+
#
|
52
|
+
# * <tt>Default:</tt> [:order_by, :order_as, :per_page]
|
53
|
+
# * <tt>Accepts:</tt> Array, nil, false
|
54
|
+
def hidden_fields=(value)
|
55
|
+
@hidden_fields = value
|
56
|
+
end
|
57
|
+
|
46
58
|
def page_links_first # :nodoc:
|
47
59
|
@page_links_first
|
48
60
|
end
|
@@ -80,7 +92,7 @@ module Searchgasm
|
|
80
92
|
end
|
81
93
|
|
82
94
|
def page_links_outer_spread # :nodoc:
|
83
|
-
@page_links_outer_spread ||=
|
95
|
+
@page_links_outer_spread ||= 1
|
84
96
|
end
|
85
97
|
|
86
98
|
# The default for the :outer_spread option for the page_links helper.
|
@@ -116,7 +128,7 @@ module Searchgasm
|
|
116
128
|
end
|
117
129
|
|
118
130
|
def per_page # :nodoc:
|
119
|
-
@per_page ||= per_page_choices[
|
131
|
+
@per_page ||= per_page_choices[1]
|
120
132
|
end
|
121
133
|
|
122
134
|
# The default for per page. This is only applicaple for protected searches. Meaning you start the search with new_search or new_conditions.
|
@@ -141,18 +153,6 @@ module Searchgasm
|
|
141
153
|
def per_page_choices=(value)
|
142
154
|
@per_page_choices = value
|
143
155
|
end
|
144
|
-
|
145
|
-
def hidden_fields # :nodoc:
|
146
|
-
@hidden_fields ||= (Search::Base::SPECIAL_FIND_OPTIONS - [:page])
|
147
|
-
end
|
148
|
-
|
149
|
-
# Which hidden fields to automatically include when creating a form with a Searchgasm object. See Searchgasm::Helpers::Form for more info.
|
150
|
-
#
|
151
|
-
# * <tt>Default:</tt> [:order_by, :order_as, :per_page]
|
152
|
-
# * <tt>Accepts:</tt> Array, nil, false
|
153
|
-
def hidden_fields=(value)
|
154
|
-
@hidden_fields = value
|
155
|
-
end
|
156
156
|
end
|
157
157
|
end
|
158
158
|
end
|
@@ -1,5 +1,56 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Helpers
|
3
|
+
# = Control Type Helpers
|
4
|
+
#
|
5
|
+
# The purpose of these helpers is to make ordering and paginating data, in your view, a breeze. Everyone has their own flavor of displaying data, so I made these helpers extra flexible, just for you.
|
6
|
+
#
|
7
|
+
# === Tutorial
|
8
|
+
#
|
9
|
+
# Check out my tutorial on how to implement searchgasm into a rails app: http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchgasm
|
10
|
+
#
|
11
|
+
# === How it's organized
|
12
|
+
#
|
13
|
+
# If we break it down, you can do 4 different things with your data in your view:
|
14
|
+
#
|
15
|
+
# 1. Order your data by a single column or an array of columns
|
16
|
+
# 2. Descend or ascend your data
|
17
|
+
# 3. Change how many items are on each page
|
18
|
+
# 4. Paginate through your data
|
19
|
+
#
|
20
|
+
# Each one of these actions comes with 3 different types of helpers:
|
21
|
+
#
|
22
|
+
# 1. Link - A single link for a single value. Requires that you pass a value as the first parameter.
|
23
|
+
# 2. Links - A group of single links.
|
24
|
+
# 3. Select - A select with choices that perform an action once selected. Basically the same thing as a group of links, but just as a select form element
|
25
|
+
# 4. Remote - lets you prefix any of these helpers with "remote_" and it will use the built in rails ajax helpers. I highly recommend unobstrusive javascript though, using jQuery.
|
26
|
+
#
|
27
|
+
# === Examples
|
28
|
+
#
|
29
|
+
# Sometimes the best way to explain something is with some examples. Let's pretend we are performing these actions on a User model. Check it out:
|
30
|
+
#
|
31
|
+
# order_by_link(:name)
|
32
|
+
# => produces a single link that when clicked will order by the name column, and each time its clicked alternated between "ASC" and "DESC"
|
33
|
+
#
|
34
|
+
# order_by_links
|
35
|
+
# => produces a group of links for all of the columns in your users table, each link is basically order_by_link(column.name)
|
36
|
+
#
|
37
|
+
# order_by_select
|
38
|
+
# => produces a select form element with all of the user's columns as choices, when the value is change (onchange) it will act as if they clicked a link.
|
39
|
+
# => This is just order_by_links as a select form element, nothing fancy
|
40
|
+
#
|
41
|
+
# What about paginating? I got you covered:
|
42
|
+
#
|
43
|
+
# page_link(2)
|
44
|
+
# => creates a link to page 2
|
45
|
+
#
|
46
|
+
# page_links
|
47
|
+
# => creates a group of links for pages, similar to a flickr style of pagination
|
48
|
+
#
|
49
|
+
# page_select
|
50
|
+
# => creates a drop down instead of a group of links. The user can select the page in the drop down and it will be as if they clicked a link for that page.
|
51
|
+
#
|
52
|
+
# You can apply the _link, _links, or _select to any of the following: order_by, order_as, per_page, page. You have your choice on how you want to set up the interface. For more information and options on these individual
|
53
|
+
# helpers check out their source files. Look at the sub modules under this one (Ex: Searchgasm::Helpers::ControlTypes::Select)
|
3
54
|
module ControlTypes
|
4
55
|
# = Link Control Types
|
5
56
|
#
|
@@ -29,6 +80,7 @@ module Searchgasm
|
|
29
80
|
# === Advanced Options
|
30
81
|
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base leve in params such as params[:page], params[:per_page], etc, then set this to nil.
|
31
82
|
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
83
|
+
# * <tt>:url_params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
32
84
|
def order_by_link(order_by, options = {})
|
33
85
|
order_by = deep_stringify(order_by)
|
34
86
|
add_order_by_link_defaults!(order_by, options)
|
@@ -58,6 +110,7 @@ module Searchgasm
|
|
58
110
|
# === Advanced Options
|
59
111
|
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base leve in params such as params[:page], params[:per_page], etc, then set this to nil.
|
60
112
|
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
113
|
+
# * <tt>:url_params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
61
114
|
def order_as_link(order_as, options = {})
|
62
115
|
add_order_as_link_defaults!(order_as, options)
|
63
116
|
html = searchgasm_state_for(:order_as, options)
|
@@ -88,6 +141,7 @@ module Searchgasm
|
|
88
141
|
# === Advanced Options
|
89
142
|
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base leve in params such as params[:page], params[:per_page], etc, then set this to nil.
|
90
143
|
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
144
|
+
# * <tt>:url_params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
91
145
|
def per_page_link(per_page, options = {})
|
92
146
|
add_per_page_link_defaults!(per_page, options)
|
93
147
|
html = searchgasm_state_for(:per_page, options)
|
@@ -116,6 +170,7 @@ module Searchgasm
|
|
116
170
|
# === Advanced Options
|
117
171
|
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base leve in params such as params[:page], params[:per_page], etc, then set this to nil.
|
118
172
|
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
173
|
+
# * <tt>:url_params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
119
174
|
def page_link(page, options = {})
|
120
175
|
add_page_link_defaults!(page, options)
|
121
176
|
html = searchgasm_state_for(:page, options)
|
@@ -90,15 +90,10 @@ module Searchgasm
|
|
90
90
|
#
|
91
91
|
# Please look at per_page_link. All options there are applicable here and are passed onto each option.
|
92
92
|
#
|
93
|
-
# * <tt>:inner_spread</tt> -- default: 3, set to nil to show all pages,
|
94
|
-
# * <tt>:outer_spread</tt> -- default: 1, set to nil to disable,
|
95
|
-
# *
|
96
|
-
# *
|
97
|
-
# * "< Prev 1 ... 3 4 [5] 6 7 ... 10 Next >" for :outer_spread = 1 and :inner_spread = 3
|
98
|
-
# * "< Prev 1 2 ... 3 4 [5] 6 7 ... 9 10 Next >" for :outer_spread = 2 and :inner_spread = 3 (outer_spread = number of absolute pages on each side)
|
99
|
-
# * Outer spread pages will not be visible unless the current_page is more than :inner_spread away from the first or last page.
|
100
|
-
# * <tt>:prev</tt> -- default: < Prev, set to nil to omit. This is an extra link on the left side of the page links that will go to the previous page
|
101
|
-
# * <tt>:next</tt> -- default: Next >, set to nil to omit. This is an extra link on the right side of the page links that will go to the next page
|
93
|
+
# * <tt>:inner_spread</tt> -- default: 3, set to nil to show all pages, set 0 to show no page links. This represents how many choices available on each side of the current page
|
94
|
+
# * <tt>:outer_spread</tt> -- default: 1, set to nil to disable, set to 0 show no outer spread but the separator will still be present. This represents how many choices are in the "outer" spread.
|
95
|
+
# * <tt>:prev</tt> -- default: "< Prev", set to nil to omit. This is an extra link on the left side of the page links that will go to the previous page
|
96
|
+
# * <tt>:next</tt> -- default: "Next >", set to nil to omit. This is an extra link on the right side of the page links that will go to the next page
|
102
97
|
# * <tt>:first</tt> -- default: nil, set to nil to omit. This is an extra link on thefar left side of the page links that will go to the first page
|
103
98
|
# * <tt>:last</tt> -- default: nil, set to nil to omit. This is an extra link on the far right side of the page links that will go to the last page
|
104
99
|
def page_links(options = {})
|
@@ -8,25 +8,25 @@ module Searchgasm
|
|
8
8
|
# Please see order_by_links. All options are the same and applicable here. The only difference is that instead of a group of links, this gets returned as a select form element that will perform the same function when the value is changed.
|
9
9
|
def order_by_select(options = {})
|
10
10
|
add_order_by_select_defaults!(options)
|
11
|
-
searchgasm_state_for(:order_by, options) + select(options[:params_scope], :order_by, options[:choices], options[:tag]
|
11
|
+
searchgasm_state_for(:order_by, options) + select(options[:params_scope], :order_by, options[:choices], options[:tag], options[:html] || {})
|
12
12
|
end
|
13
13
|
|
14
14
|
# Please see order_as_links. All options are the same and applicable here. The only difference is that instead of a group of links, this gets returned as a select form element that will perform the same function when the value is changed.
|
15
15
|
def order_as_select(options = {})
|
16
16
|
add_order_by_select_defaults!(options)
|
17
|
-
searchgasm_state_for(:order_as, options) + select(options[:params_scope], :order_as, options[:choices], options[:tag]
|
17
|
+
searchgasm_state_for(:order_as, options) + select(options[:params_scope], :order_as, options[:choices], options[:tag], options[:html])
|
18
18
|
end
|
19
19
|
|
20
20
|
# Please see per_page_links. All options are the same and applicable here. The only difference is that instead of a group of links, this gets returned as a select form element that will perform the same function when the value is changed.
|
21
21
|
def per_page_select(options = {})
|
22
22
|
add_per_page_select_defaults!(options)
|
23
|
-
searchgasm_state_for(:per_page, options) + select(options[:params_scope], :per_page, options[:choices], options[:tag]
|
23
|
+
searchgasm_state_for(:per_page, options) + select(options[:params_scope], :per_page, options[:choices], options[:tag], options[:html])
|
24
24
|
end
|
25
25
|
|
26
26
|
# Please see page_links. All options are the same and applicable here, excep the :prev, :next, :first, and :last options. The only difference is that instead of a group of links, this gets returned as a select form element that will perform the same function when the value is changed.
|
27
27
|
def page_select(options = {})
|
28
28
|
add_page_select_defaults!(options)
|
29
|
-
searchgasm_state_for(:page, options) + select(options[:params_scope], :page, (options[:first_page]..options[:last_page]), options[:tag]
|
29
|
+
searchgasm_state_for(:page, options) + select(options[:params_scope], :page, (options[:first_page]..options[:last_page]), options[:tag], options[:html])
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
@@ -56,6 +56,9 @@ module Searchgasm
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def add_searchgasm_select_defaults!(option, options)
|
59
|
+
options[:tag] ||= {}
|
60
|
+
options[:tag][:object] = options[:search_obj]
|
61
|
+
|
59
62
|
url = searchgasm_url_hash(option, nil, options)
|
60
63
|
url.delete(option)
|
61
64
|
url = searchgasm_url(url, options)
|
@@ -92,9 +92,9 @@ module Searchgasm
|
|
92
92
|
options[:html][:onsubmit] += ";"
|
93
93
|
|
94
94
|
javascript = "if(typeof(Prototype) != 'undefined') {"
|
95
|
-
search_options[:hidden_fields].each { |field| javascript += "$('#{name}_#{field}
|
95
|
+
search_options[:hidden_fields].each { |field| javascript += "field = $('#{name}_#{field}'); if(field) { $('#{name}_#{field}_hidden').value = field.value; }" }
|
96
96
|
javascript += "} else if(jQuery) {"
|
97
|
-
search_options[:hidden_fields].each { |field| javascript += "$('##{name}_#{field}
|
97
|
+
search_options[:hidden_fields].each { |field| javascript += "field = $('##{name}_#{field}'); if(field) { $('##{name}_#{field}_hidden').val(field.val()); }" }
|
98
98
|
javascript += "}"
|
99
99
|
|
100
100
|
options[:html][:onsubmit] += javascript
|
@@ -6,7 +6,7 @@ module Searchgasm
|
|
6
6
|
def add_searchgasm_helper_defaults!(option, options)
|
7
7
|
options[:params_scope] = :search unless options.has_key?(:params_scope)
|
8
8
|
options[:search_obj] ||= instance_variable_get("@#{options[:params_scope]}")
|
9
|
-
raise(ArgumentError, "@search object could not be inferred, please specify: :search_obj => @search") unless options[:search_obj].is_a?(Searchgasm::Search::Base)
|
9
|
+
raise(ArgumentError, "@search object could not be inferred, please specify: :search_obj => @search or :params_scope => :search_obj_name") unless options[:search_obj].is_a?(Searchgasm::Search::Base)
|
10
10
|
options[:html] ||= {}
|
11
11
|
options[:html][:class] ||= ""
|
12
12
|
searchgasm_add_class!(options[:html], option)
|
@@ -14,7 +14,8 @@ module Searchgasm
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def searchgasm_url(url_hash, options)
|
17
|
-
options[:params_scope].blank? ? url_hash : {options[:params_scope] => url_hash}
|
17
|
+
url = options[:params_scope].blank? ? url_hash : {options[:params_scope] => url_hash}
|
18
|
+
!options[:url_params].is_a?(Hash) ? url : url.merge(options[:url_params])
|
18
19
|
end
|
19
20
|
|
20
21
|
def searchgasm_url_hash(option, value, options)
|
@@ -13,7 +13,7 @@ module Searchgasm #:nodoc:
|
|
13
13
|
AR_FIND_OPTIONS = ::ActiveRecord::Base.valid_find_options
|
14
14
|
|
15
15
|
# Options ActiveRecord allows when performing calculations
|
16
|
-
AR_CALCULATIONS_OPTIONS = ::ActiveRecord::Base.valid_calculations_options
|
16
|
+
AR_CALCULATIONS_OPTIONS = (::ActiveRecord::Base.valid_calculations_options - [:select, :limit, :offset, :order, :group])
|
17
17
|
|
18
18
|
AR_OPTIONS = (AR_FIND_OPTIONS + AR_CALCULATIONS_OPTIONS).uniq
|
19
19
|
|
@@ -64,6 +64,11 @@ module Searchgasm #:nodoc:
|
|
64
64
|
"#<#{klass}Search #{current_find_options.inspect}>"
|
65
65
|
end
|
66
66
|
|
67
|
+
# need to remote any duplicate joins that are specified in includes
|
68
|
+
#def joins
|
69
|
+
# # If includes are specified, remove the joins
|
70
|
+
#end
|
71
|
+
|
67
72
|
def limit=(value)
|
68
73
|
@set_limit = true
|
69
74
|
@limit = value.blank? || value == 0 ? nil : value.to_i
|
@@ -77,7 +82,7 @@ module Searchgasm #:nodoc:
|
|
77
82
|
def offset=(value)
|
78
83
|
@offset = value.blank? ? nil : value.to_i
|
79
84
|
end
|
80
|
-
|
85
|
+
|
81
86
|
def options=(values)
|
82
87
|
return unless values.is_a?(Hash)
|
83
88
|
values.symbolize_keys.fast_assert_valid_keys(OPTIONS)
|
@@ -93,11 +98,24 @@ module Searchgasm #:nodoc:
|
|
93
98
|
# Sanitizes everything down into options ActiveRecord::Base.find can understand
|
94
99
|
def sanitize(searching = true)
|
95
100
|
find_options = {}
|
101
|
+
|
96
102
|
(searching ? AR_FIND_OPTIONS : AR_CALCULATIONS_OPTIONS).each do |find_option|
|
97
103
|
value = send(find_option)
|
98
104
|
next if value.blank?
|
99
105
|
find_options[find_option] = value
|
100
106
|
end
|
107
|
+
|
108
|
+
unless find_options[:joins].blank?
|
109
|
+
# The following is to return uniq records since we are using joins instead of includes
|
110
|
+
if searching
|
111
|
+
find_options[:group] ||= "#{quote_table_name(klass.table_name)}.#{quote_column_name(klass.primary_key)}"
|
112
|
+
else
|
113
|
+
# If we are calculating use includes because they use joins that grab uniq records. When calculating, includes don't have the
|
114
|
+
# performance hit that they have when searching. Plus it's cleaner.
|
115
|
+
find_options[:include] = merge_joins(find_options[:include], find_options.delete(:joins))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
101
119
|
find_options
|
102
120
|
end
|
103
121
|
|