searchgasm 1.0.2 → 1.0.3
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 +12 -2
- data/Manifest +5 -4
- data/README.rdoc +15 -17
- data/Rakefile +1 -2
- data/lib/searchgasm/active_record/associations.rb +19 -31
- data/lib/searchgasm/active_record/base.rb +40 -9
- data/lib/searchgasm/condition/base.rb +1 -1
- data/lib/searchgasm/condition/inclusive_descendant_of.rb +0 -2
- data/lib/searchgasm/condition/sibling_of.rb +0 -2
- data/lib/searchgasm/conditions/base.rb +21 -34
- data/lib/searchgasm/conditions/protection.rb +8 -2
- data/lib/searchgasm/helpers/control_types/links.rb +9 -6
- data/lib/searchgasm/helpers/control_types/remote_link.rb +1 -0
- data/lib/searchgasm/helpers/control_types/remote_links.rb +3 -0
- data/lib/searchgasm/helpers/control_types/remote_select.rb +3 -0
- data/lib/searchgasm/helpers/control_types/select.rb +3 -0
- data/lib/searchgasm/helpers/form.rb +11 -4
- data/lib/searchgasm/search/base.rb +26 -46
- data/lib/searchgasm/search/conditions.rb +4 -1
- data/lib/searchgasm/search/pagination.rb +2 -1
- data/lib/searchgasm/search/scoping.rb +0 -0
- data/lib/searchgasm/search.rb +7 -0
- data/lib/searchgasm/shared/searching.rb +25 -0
- data/lib/searchgasm/shared/utilities.rb +32 -0
- data/lib/searchgasm/shared/virtual_classes.rb +39 -0
- data/lib/searchgasm/version.rb +1 -1
- data/lib/searchgasm.rb +6 -2
- data/searchgasm.gemspec +15 -10
- data/test/test_active_record_associations.rb +18 -1
- data/test/test_conditions_base.rb +19 -11
- data/test/test_search_base.rb +8 -8
- metadata +14 -9
- data/benchmarks/benchmark.rb +0 -43
- data/benchmarks/benchmark_helper.rb +0 -52
- data/benchmarks/profile.rb +0 -15
- data/lib/searchgasm/utilities.rb +0 -30
data/CHANGELOG.rdoc
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
+
== 1.0.3 released 2008-09-18
|
2
|
+
|
3
|
+
* Updated inspect to show the current options for your search. Plays nicer in the console.
|
4
|
+
* Made sure protection state is persistent among relationship conditions.
|
5
|
+
* Fixed bug with backwards compatibility of rails. concat requires a proc in older version.
|
6
|
+
* Defaulted remote control types to use GET requests instead of POST.
|
7
|
+
* Completely reengineered integration with ActiveRecord. Searchgasm is properly using scopes letting you do use serachgasm where scope are implemented. @current_users.orders.new_search, etc. If your search is scoped and you want a search object, that search object will represent a new search in the context of those scopes, meaning the scopes get merged into Searchgasm as options.
|
8
|
+
* Dropped support for Searchgasm functionality when defining relationships: has_many :order, :conditions => {:total_gt => 100}, will not work anymore. It's a chicken and the egg thing. Searchgasm needs AR constants, some models get loaded before others, therefore the Order model may not have been loaded yet, causing an unknown constant error.
|
9
|
+
* Clean up redundant code and moved it into the Searchgasm::Shared namespace.
|
10
|
+
|
1
11
|
== 1.0.2 released 2008-09-12
|
2
12
|
|
3
13
|
* Moved cached searchers out of the global namespace and into the Searchgasm::Cache namespce.
|
4
|
-
* Various changes to improve performance
|
14
|
+
* Various changes to improve performance through profiling / benchmarking. http://pastie.org/271936
|
5
15
|
* Config.per_page works with new_search & new_search! only. Where as before it was only working if the search was protected.
|
6
16
|
|
7
17
|
== 1.0.1 released 2008-09-11
|
@@ -50,7 +60,7 @@
|
|
50
60
|
== 0.9.4 released 2008-09-03
|
51
61
|
|
52
62
|
* Cleaned up search methods
|
53
|
-
* Removed reset!method for both searching and searching by conditions
|
63
|
+
* Removed reset! method for both searching and searching by conditions
|
54
64
|
|
55
65
|
== 0.9.3 released 2008-09-02
|
56
66
|
|
data/Manifest
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
benchmarks/benchmark.rb
|
2
|
-
benchmarks/benchmark_helper.rb
|
3
|
-
benchmarks/profile.rb
|
4
1
|
CHANGELOG.rdoc
|
5
2
|
examples/README.rdoc
|
6
3
|
init.rb
|
@@ -42,7 +39,11 @@ lib/searchgasm/search/conditions.rb
|
|
42
39
|
lib/searchgasm/search/ordering.rb
|
43
40
|
lib/searchgasm/search/pagination.rb
|
44
41
|
lib/searchgasm/search/protection.rb
|
45
|
-
lib/searchgasm/
|
42
|
+
lib/searchgasm/search/scoping.rb
|
43
|
+
lib/searchgasm/search.rb
|
44
|
+
lib/searchgasm/shared/searching.rb
|
45
|
+
lib/searchgasm/shared/utilities.rb
|
46
|
+
lib/searchgasm/shared/virtual_classes.rb
|
46
47
|
lib/searchgasm/version.rb
|
47
48
|
lib/searchgasm.rb
|
48
49
|
Manifest
|
data/README.rdoc
CHANGED
@@ -219,14 +219,23 @@ For tree data structures you get a few nifty methods. Let's assume Users is a tr
|
|
219
219
|
User.all(:conditions => {:inclusive_descendant_of => User.roots.first.id})
|
220
220
|
|
221
221
|
|
222
|
-
==
|
222
|
+
== Scope support
|
223
223
|
|
224
|
-
Not only can you use searchgasm when searching, but you can use it when
|
224
|
+
Not only can you use searchgasm when searching, but you can use it when using scopes.
|
225
225
|
|
226
226
|
class User < ActiveRecord::Base
|
227
|
-
has_many :expensive_pending_orders, :conditions => {:total_greater_than => 1_000_000, :state => :pending}, :per_page => 20
|
228
227
|
named_scope :sexy, :conditions => {:first_name => "Ben", email_ends_with => "binarylogic.com"}, :per_page => 20
|
229
228
|
end
|
229
|
+
|
230
|
+
or
|
231
|
+
|
232
|
+
class User < ActiveRecord::Base
|
233
|
+
def self.find_sexy
|
234
|
+
with_scope(:find => {:conditions => {:first_name => "Ben", email_ends_with => "binarylogic.com"}, :per_page => 20}) do
|
235
|
+
all
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
230
239
|
|
231
240
|
== Always use protection...against SQL injections
|
232
241
|
|
@@ -328,22 +337,11 @@ Pretty nifty, huh? You can create any condition ultimately creating any SQL you
|
|
328
337
|
|
329
338
|
== Under the hood
|
330
339
|
|
331
|
-
I'm a big fan of understanding what I'm using, so here's a quick explanation: The design behind this plugin is pretty simple
|
332
|
-
|
333
|
-
== Performance / Benchmarking
|
334
|
-
|
335
|
-
I ran searchgasm through some performance tests using ruby-prof. After working on it for a little while I improved performance quite a bit. Notice the "2nd instantiation" report. This is implementing caching and skips all dynamic method creation / meta programming. It resulted in code over 50 times faster.
|
340
|
+
I'm a big fan of understanding what I'm using, so here's a quick explanation: The design behind this plugin is pretty simple and I had 1 main rule when developing this:
|
336
341
|
|
337
|
-
|
338
|
-
1st instantiation: 0.000000 0.000000 0.000000 ( 0.005466)
|
339
|
-
2nd instantiation: 0.000000 0.000000 0.000000 ( 0.000108)
|
340
|
-
Local ordering: 0.000000 0.000000 0.000000 ( 0.000265)
|
341
|
-
Advanced ordering: 0.000000 0.000000 0.000000 ( 0.000413)
|
342
|
-
Local conditions: 0.000000 0.000000 0.000000 ( 0.000241)
|
343
|
-
Advanced conditions: 0.000000 0.000000 0.000000 ( 0.000602)
|
344
|
-
Its complicated: 0.000000 0.000000 0.000000 ( 0.001017)
|
342
|
+
ActiveRecord should never know about Searchgasm
|
345
343
|
|
346
|
-
|
344
|
+
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.
|
347
345
|
|
348
346
|
== Reporting problems / bugs
|
349
347
|
|
data/Rakefile
CHANGED
@@ -8,8 +8,7 @@ Echoe.new 'searchgasm' do |p|
|
|
8
8
|
p.author = "Ben Johnson of Binary Logic"
|
9
9
|
p.email = 'bjohnson@binarylogic.com'
|
10
10
|
p.project = 'searchgasm'
|
11
|
-
p.summary = "
|
12
|
-
p.description = "Makes ActiveRecord searching easier, robust, and powerful. Automatic conditions, pagination support, object based searching, and more."
|
11
|
+
p.summary = "Object based ActiveRecord searching, ordering, pagination, and more!"
|
13
12
|
p.url = "http://github.com/binarylogic/searchgasm"
|
14
13
|
p.dependencies = %w(activerecord activesupport)
|
15
14
|
p.include_rakefile = true
|
@@ -5,68 +5,56 @@ module Searchgasm
|
|
5
5
|
# These methods hook into ActiveRecords association methods and add in searchgasm functionality.
|
6
6
|
module Associations
|
7
7
|
module AssociationCollection
|
8
|
-
# This
|
8
|
+
# This needs to be implemented because AR doesn't leverage scopes with this method like it probably should
|
9
9
|
def find_with_searchgasm(*args)
|
10
10
|
options = args.extract_options!
|
11
11
|
args << sanitize_options_with_searchgasm(options)
|
12
12
|
find_without_searchgasm(*args)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
# See build_conditions under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
16
16
|
def build_conditions(options = {}, &block)
|
17
|
-
|
18
|
-
conditions.scope = scope(:find)[:conditions]
|
19
|
-
conditions
|
17
|
+
@reflection.klass.send(:with_scope, :find => construct_scope[:find]) { @reflection.klass.build_conditions(options, &block) }
|
20
18
|
end
|
21
|
-
|
19
|
+
|
22
20
|
# See build_conditions! under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
23
21
|
def build_conditions!(options = {}, &block)
|
24
|
-
|
25
|
-
conditions.scope = scope(:find)[:conditions]
|
26
|
-
conditions
|
22
|
+
@reflection.klass.send(:with_scope, :find => construct_scope[:find]) { @reflection.klass.build_conditions!(options, &block) }
|
27
23
|
end
|
28
|
-
|
24
|
+
|
29
25
|
# See build_search under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
30
26
|
def build_search(options = {}, &block)
|
31
|
-
|
32
|
-
conditions.scope = scope(:find)[:conditions]
|
33
|
-
conditions
|
27
|
+
@reflection.klass.send(:with_scope, :find => construct_scope[:find]) { @reflection.klass.build_search(options, &block) }
|
34
28
|
end
|
35
|
-
|
29
|
+
|
36
30
|
# See build_conditions! under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
37
31
|
def build_search!(options = {}, &block)
|
38
|
-
|
39
|
-
conditions.scope = scope(:find)[:conditions]
|
40
|
-
conditions
|
32
|
+
@reflection.klass.send(:with_scope, :find => construct_scope[:find]) { @reflection.klass.build_search!(options, &block) }
|
41
33
|
end
|
42
34
|
end
|
43
|
-
|
44
|
-
module
|
45
|
-
# This is an alias method chain. It hook into ActiveRecord's "calculate" method for has many associations and checks to see if Searchgasm should get involved.
|
35
|
+
|
36
|
+
module Shared
|
46
37
|
def count_with_searchgasm(*args)
|
47
|
-
|
48
|
-
|
38
|
+
options = args.extract_options!
|
39
|
+
args << sanitize_options_with_searchgasm(options)
|
40
|
+
count_without_searchgasm(*args)
|
49
41
|
end
|
50
42
|
end
|
51
43
|
end
|
52
44
|
end
|
53
45
|
end
|
54
46
|
|
55
|
-
ActiveRecord::Associations::AssociationCollection.send(:include, Searchgasm::ActiveRecord::Associations::AssociationCollection)
|
56
|
-
|
57
47
|
module ActiveRecord
|
58
48
|
module Associations
|
59
49
|
class AssociationCollection
|
50
|
+
include Searchgasm::ActiveRecord::Associations::AssociationCollection
|
51
|
+
|
60
52
|
alias_method_chain :find, :searchgasm
|
61
53
|
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
ActiveRecord::Associations::HasManyAssociation.send(:include, Searchgasm::ActiveRecord::Associations::HasManyAssociation)
|
66
|
-
|
67
|
-
module ActiveRecord
|
68
|
-
module Associations
|
54
|
+
|
69
55
|
class HasManyAssociation
|
56
|
+
include Searchgasm::ActiveRecord::Associations::Shared
|
57
|
+
|
70
58
|
alias_method_chain :count, :searchgasm
|
71
59
|
end
|
72
60
|
end
|
@@ -18,21 +18,29 @@ module Searchgasm
|
|
18
18
|
args << options
|
19
19
|
find_without_searchgasm(*args)
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
# This is an alias method chain. It hooks into ActiveRecord's scopes and checks to see if Searchgasm should get involved. Allowing you to use all of Searchgasms conditions and tools
|
23
23
|
# in scopes as well.
|
24
24
|
#
|
25
25
|
# === Examples
|
26
26
|
#
|
27
|
+
# Named scopes:
|
28
|
+
#
|
27
29
|
# named_scope :top_expensive, :conditions => {:total_gt => 1_000_000}, :per_page => 10
|
30
|
+
# named_scope :top_expensive_ordered, :conditions => {:total_gt => 1_000_000}, :per_page => 10, :order_by => {:user => :first_name}
|
31
|
+
#
|
32
|
+
# Good ole' regular scopes:
|
28
33
|
#
|
29
34
|
# with_scope(:find => {:conditions => {:total_gt => 1_000_000}, :per_page => 10}) do
|
30
35
|
# find(:all)
|
31
36
|
# end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
#
|
38
|
+
# with_scope(:find => {:conditions => {:total_gt => 1_000_000}, :per_page => 10}) do
|
39
|
+
# build_search
|
40
|
+
# end
|
41
|
+
def with_scope_with_searchgasm(method_scoping = {}, action = :merge, &block)
|
42
|
+
method_scoping[:find] = sanitize_options_with_searchgasm(method_scoping[:find]) if method_scoping[:find]
|
43
|
+
with_scope_without_searchgasm(method_scoping, action, &block)
|
36
44
|
end
|
37
45
|
|
38
46
|
# This is a special method that Searchgasm adds in. It returns a new conditions object on the model. So you can search by conditions *only*.
|
@@ -118,17 +126,40 @@ module Searchgasm
|
|
118
126
|
private
|
119
127
|
def sanitize_options_with_searchgasm(options = {})
|
120
128
|
return options unless Searchgasm::Search::Base.needed?(self, options)
|
121
|
-
search =
|
129
|
+
search = Searchgasm::Search::Base.create_virtual_class(self).new(options) # call explicitly to avoid merging the scopes into the searcher
|
122
130
|
search.acting_as_filter = true
|
123
131
|
search.sanitize
|
124
132
|
end
|
125
133
|
|
126
134
|
def searchgasm_conditions(options = {})
|
127
|
-
Searchgasm::Conditions::Base.create_virtual_class(self).new(options)
|
135
|
+
conditions = Searchgasm::Conditions::Base.create_virtual_class(self).new(options)
|
136
|
+
conditions.conditions = (scope(:find) || {})[:conditions]
|
137
|
+
conditions
|
128
138
|
end
|
129
139
|
|
130
140
|
def searchgasm_searcher(options = {})
|
131
|
-
Searchgasm::Search::Base.create_virtual_class(self).new(options)
|
141
|
+
search = Searchgasm::Search::Base.create_virtual_class(self).new(options)
|
142
|
+
options_from_scope_for_searchgasm(options).each { |option, value| search.send("#{option}=", value) }
|
143
|
+
search
|
144
|
+
end
|
145
|
+
|
146
|
+
def options_from_scope_for_searchgasm(options)
|
147
|
+
# The goal here is to mimic how scope work. Merge what scopes would and don't what they wouldn't.
|
148
|
+
scope = scope(:find) || {}
|
149
|
+
scope_options = {}
|
150
|
+
[:group, :include, :select, :readonly].each { |option| scope_options[option] = scope[option] if !options.has_key?(option) && scope.has_key?(option) }
|
151
|
+
|
152
|
+
if scope[:joins] || options[:joins]
|
153
|
+
scope_options[:joins] = []
|
154
|
+
scope_options[:joins] += scope[:joins].is_a?(Array) ? scope[:joins] : [scope[:joins]] unless scope[:joins].blank?
|
155
|
+
scope_options[:joins] += options[:joins].is_a?(Array) ? options[:joins] : [options[:joins]] unless options[:joins].blank?
|
156
|
+
end
|
157
|
+
|
158
|
+
scope_options[:limit] = scope[:limit] if !options.has_key?(:per_page) && !options.has_key?(:limit) && scope.has_key?(:per_page)
|
159
|
+
scope_options[:offset] = scope[:offset] if !options.has_key?(:page) && !options.has_key?(:offset) && scope.has_key?(:offset)
|
160
|
+
scope_options[:order] = scope[:order] if !options.has_key?(:order_by) && !options.has_key?(:order) && scope.has_key?(:order)
|
161
|
+
scope_options[:conditions] = scope[:conditions] if scope.has_key?(:conditions)
|
162
|
+
scope_options
|
132
163
|
end
|
133
164
|
end
|
134
165
|
end
|
@@ -141,7 +172,7 @@ module ActiveRecord #:nodoc: all
|
|
141
172
|
class << self
|
142
173
|
alias_method_chain :calculate, :searchgasm
|
143
174
|
alias_method_chain :find, :searchgasm
|
144
|
-
alias_method_chain :
|
175
|
+
alias_method_chain :with_scope, :searchgasm
|
145
176
|
alias_method :new_conditions, :build_conditions
|
146
177
|
alias_method :new_conditions!, :build_conditions!
|
147
178
|
alias_method :new_search, :build_search
|
@@ -5,7 +5,7 @@ module Searchgasm
|
|
5
5
|
# The base class for creating a condition. Your custom conditions should extend this class.
|
6
6
|
# See Searchgasm::Conditions::Base.register_condition on how to write your own condition.
|
7
7
|
class Base
|
8
|
-
include Utilities
|
8
|
+
include Shared::Utilities
|
9
9
|
|
10
10
|
attr_accessor :column, :klass
|
11
11
|
attr_reader :value
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Condition
|
3
3
|
class SiblingOf < Tree
|
4
|
-
include Searchgasm::Utilities
|
5
|
-
|
6
4
|
def to_conditions(value)
|
7
5
|
parent_association = klass.reflect_on_association(:parent)
|
8
6
|
foreign_key_name = (parent_association && parent_association.options[:foreign_key]) || "parent_id"
|
@@ -5,9 +5,11 @@ 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 Utilities
|
8
|
+
include Searchgasm::Shared::Utilities
|
9
|
+
include Searchgasm::Shared::Searching
|
10
|
+
include Searchgasm::Shared::VirtualClasses
|
9
11
|
|
10
|
-
attr_accessor :relationship_name, :
|
12
|
+
attr_accessor :relationship_name, :sql
|
11
13
|
|
12
14
|
class << self
|
13
15
|
attr_accessor :added_klass_conditions, :added_column_conditions, :added_associations
|
@@ -64,37 +66,14 @@ module Searchgasm
|
|
64
66
|
|
65
67
|
def needed?(model_class, conditions) # :nodoc:
|
66
68
|
if conditions.is_a?(Hash)
|
69
|
+
column_names = model_class.column_names
|
67
70
|
conditions.stringify_keys.keys.each do |condition|
|
68
|
-
return true unless
|
71
|
+
return true unless column_names.include?(condition)
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
75
|
false
|
73
76
|
end
|
74
|
-
|
75
|
-
# Creates virtual classes for the class passed to it. This is a neccesity for keeping dynamically created method
|
76
|
-
# names specific to models. It provides caching and helps a lot with performance.
|
77
|
-
def create_virtual_class(model_class)
|
78
|
-
class_search_name = "::Searchgasm::Cache::#{model_class.name}Conditions"
|
79
|
-
|
80
|
-
begin
|
81
|
-
eval(class_search_name)
|
82
|
-
rescue NameError
|
83
|
-
eval <<-end_eval
|
84
|
-
class #{class_search_name} < ::Searchgasm::Conditions::Base
|
85
|
-
def self.klass
|
86
|
-
#{model_class.name}
|
87
|
-
end
|
88
|
-
|
89
|
-
def klass
|
90
|
-
#{model_class.name}
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
#{class_search_name}
|
95
|
-
end_eval
|
96
|
-
end
|
97
|
-
end
|
98
77
|
end
|
99
78
|
|
100
79
|
def initialize(init_conditions = {})
|
@@ -125,22 +104,29 @@ module Searchgasm
|
|
125
104
|
i.blank? ? nil : (i.size == 1 ? i.first : i)
|
126
105
|
end
|
127
106
|
|
107
|
+
def inspect
|
108
|
+
conditions_hash = conditions
|
109
|
+
conditions_hash[:sql] = sql if sql
|
110
|
+
conditions_hash[:protected] = true if protected?
|
111
|
+
conditions_hash.inspect
|
112
|
+
end
|
113
|
+
|
128
114
|
# Sanitizes the conditions down into conditions that ActiveRecord::Base.find can understand.
|
129
|
-
def sanitize
|
115
|
+
def sanitize(for_method = nil)
|
130
116
|
conditions = merge_conditions(*objects.collect { |object| object.sanitize })
|
131
|
-
return
|
132
|
-
merge_conditions(conditions,
|
117
|
+
return sql if conditions.blank?
|
118
|
+
merged_conditions = merge_conditions(conditions, sql)
|
119
|
+
for_method.blank? ? merged_conditions : {:conditions => merged_conditions}
|
133
120
|
end
|
134
121
|
|
135
|
-
# Allows you to set the conditions via a hash.
|
136
|
-
# merge it all together at the end.
|
122
|
+
# Allows you to set the conditions via a hash.
|
137
123
|
def conditions=(conditions)
|
138
124
|
case conditions
|
139
125
|
when Hash
|
140
126
|
assert_valid_conditions(conditions)
|
141
127
|
remove_conditions_from_protected_assignement(conditions).each { |condition, value| send("#{condition}=", value) }
|
142
128
|
else
|
143
|
-
self.
|
129
|
+
self.sql = conditions
|
144
130
|
end
|
145
131
|
end
|
146
132
|
|
@@ -171,8 +157,9 @@ module Searchgasm
|
|
171
157
|
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
172
158
|
def #{association.name}
|
173
159
|
if @#{association.name}.nil?
|
174
|
-
@#{association.name} = #{association.class_name}.
|
160
|
+
@#{association.name} = Searchgasm::Conditions::Base.create_virtual_class(#{association.class_name}).new
|
175
161
|
@#{association.name}.relationship_name = "#{association.name}"
|
162
|
+
@#{association.name}.protect = protect
|
176
163
|
objects << @#{association.name}
|
177
164
|
end
|
178
165
|
@#{association.name}
|
@@ -6,7 +6,7 @@ module Searchgasm
|
|
6
6
|
module Protection
|
7
7
|
def self.included(klass)
|
8
8
|
klass.class_eval do
|
9
|
-
|
9
|
+
attr_reader :protect
|
10
10
|
alias_method_chain :conditions=, :protection
|
11
11
|
end
|
12
12
|
end
|
@@ -15,16 +15,22 @@ module Searchgasm
|
|
15
15
|
unless conditions.is_a?(Hash)
|
16
16
|
if protect?
|
17
17
|
return if conditions.blank?
|
18
|
-
raise(ArgumentError, "You can not
|
18
|
+
raise(ArgumentError, "You can not pass SQL as conditions while the search is being protected, you can only pass a hash")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
self.conditions_without_protection = conditions
|
23
23
|
end
|
24
24
|
|
25
|
+
def protect=(value)
|
26
|
+
associations.each { |association| association.protect = value }
|
27
|
+
@protect = value
|
28
|
+
end
|
29
|
+
|
25
30
|
def protect?
|
26
31
|
protect == true
|
27
32
|
end
|
33
|
+
alias_method :protected?, :protect?
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Helpers
|
3
3
|
module ControlTypes
|
4
|
+
# = Links Control Types
|
5
|
+
#
|
6
|
+
# These helpers create a group of links to help navigate through search data.
|
4
7
|
module Links
|
5
8
|
# Creates a group of links that order the data by a column or columns. All that this does is loop through the :choices option and call order_by_link and then glue it all together.
|
6
9
|
#
|
@@ -11,7 +14,7 @@ module Searchgasm
|
|
11
14
|
#
|
12
15
|
# === Options
|
13
16
|
#
|
14
|
-
# Please look at order_by_link. All options there are applicable here and are passed onto each option.
|
17
|
+
# Please look at order_by_link. All options there are applicable here and are passed onto each option. Here are the options specific to this method:
|
15
18
|
#
|
16
19
|
# * <tt>:choices</tt> -- default: the models column names, the choices to loop through when calling order_by_link
|
17
20
|
def order_by_links(options = {})
|
@@ -32,7 +35,7 @@ module Searchgasm
|
|
32
35
|
#
|
33
36
|
# === Options
|
34
37
|
#
|
35
|
-
# Please look at order_as_link. All options there are applicable here and are passed onto each option.
|
38
|
+
# Please look at order_as_link. All options there are applicable here and are passed onto each option. Here are the options specific to this method:
|
36
39
|
#
|
37
40
|
# * <tt>:choices</tt> -- default: ["asc", "desc"], the choices to loop through when calling order_as_link
|
38
41
|
def order_as_links(options = {})
|
@@ -53,7 +56,7 @@ module Searchgasm
|
|
53
56
|
#
|
54
57
|
# === Options
|
55
58
|
#
|
56
|
-
# Please look at per_page_link. All options there are applicable here and are passed onto each option.
|
59
|
+
# Please look at per_page_link. All options there are applicable here and are passed onto each option. Here are the options specific to this method:
|
57
60
|
#
|
58
61
|
# * <tt>:choices</tt> -- default: [10, 25, 50, 100, 150, 200, nil], the choices to loop through when calling per_page_link.
|
59
62
|
def per_page_links(options = {})
|
@@ -88,11 +91,11 @@ module Searchgasm
|
|
88
91
|
#
|
89
92
|
# === Options
|
90
93
|
#
|
91
|
-
# Please look at per_page_link. All options there are applicable here and are passed onto each option.
|
94
|
+
# Please look at per_page_link. All options there are applicable here and are passed onto each option. Here are the options specific to this method:
|
92
95
|
#
|
93
96
|
# * <tt>:spread</tt> -- default: 3, set to nil to show all page, this represents how many choices available on each side of the current page
|
94
|
-
# * <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
|
95
|
-
# * <tt>:next</tt> -- default: Next
|
97
|
+
# * <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
|
98
|
+
# * <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
|
96
99
|
# * <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
|
97
100
|
# * <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
|
98
101
|
def page_links(options = {})
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Helpers
|
3
3
|
module ControlTypes
|
4
|
+
# = Remote Links Control Types
|
5
|
+
#
|
6
|
+
# These helpers use rails built in remote_function as links. They are the same thing as the Links control type, but just use rails built in remote helpers.
|
4
7
|
module RemoteLinks
|
5
8
|
# Same as order_by_links, but uses link_to_remote instead of remote.
|
6
9
|
#
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Helpers
|
3
3
|
module ControlTypes
|
4
|
+
# = Remote Select Control Types
|
5
|
+
#
|
6
|
+
# These helpers use rails built in remote_function as links. They are the same thing as the Select control type, but just use rails built in remote helpers.
|
4
7
|
module RemoteSelect
|
5
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.
|
6
9
|
def remote_order_by_select(options = {})
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module Helpers
|
3
3
|
module ControlTypes
|
4
|
+
# = Select Control Types
|
5
|
+
#
|
6
|
+
# These create <select> tags to help navigate through search data. This is here as an alternative to the Links control types.
|
4
7
|
module Select
|
5
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.
|
6
9
|
def order_by_select(options = {})
|
@@ -116,13 +116,20 @@ module Searchgasm
|
|
116
116
|
args
|
117
117
|
end
|
118
118
|
|
119
|
-
def insert_searchgasm_fields(args, search_object, search_options)
|
119
|
+
def insert_searchgasm_fields(args, search_object, search_options, &block)
|
120
120
|
return unless search_object.is_a?(Search::Base)
|
121
121
|
name = args.first
|
122
122
|
options = args.extract_options!
|
123
123
|
options
|
124
124
|
search_options[:hidden_fields].each do |field|
|
125
|
-
|
125
|
+
html = hidden_field(name, field, :object => search_object, :id => "#{name}_#{field}_hidden", :value => (field == :order_by ? searchgasm_order_by_value(search_object.order_by) : search_object.send(field)))
|
126
|
+
|
127
|
+
# For edge rails and older version compatibility, passing a binding to concat was deprecated
|
128
|
+
begin
|
129
|
+
concat(html)
|
130
|
+
rescue ArgumentError
|
131
|
+
concat(html, block.binding)
|
132
|
+
end
|
126
133
|
end
|
127
134
|
args << options
|
128
135
|
end
|
@@ -136,7 +143,7 @@ module Searchgasm
|
|
136
143
|
if search_object
|
137
144
|
searchgasm_options = extract_searchgasm_options!(args)
|
138
145
|
new_args = searchgasm_args(args, search_object, searchgasm_options, :fields_for)
|
139
|
-
insert_searchgasm_fields(new_args, search_object, searchgasm_options)
|
146
|
+
insert_searchgasm_fields(new_args, search_object, searchgasm_options, &block)
|
140
147
|
fields_for_without_searchgasm(*new_args, &block)
|
141
148
|
else
|
142
149
|
fields_for_without_searchgasm(*args, &block)
|
@@ -172,7 +179,7 @@ module Searchgasm
|
|
172
179
|
if search_object
|
173
180
|
searchgasm_options = extract_searchgasm_options!(args)
|
174
181
|
new_args = searchgasm_args(args, search_object, searchgasm_options, :fields_for)
|
175
|
-
insert_searchgasm_fields(new_args, search_object, searchgasm_options)
|
182
|
+
insert_searchgasm_fields(new_args, search_object, searchgasm_options, &block)
|
176
183
|
fields_for_without_searchgasm(*new_args, &block)
|
177
184
|
else
|
178
185
|
fields_for_without_searchgasm(*args, &block)
|