searchgasm 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|