searchgasm 0.9.6 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Manifest +34 -21
- data/{README.mdown → README.rdoc} +96 -63
- data/Rakefile +1 -1
- data/examples/README.rdoc +4 -0
- data/lib/searchgasm/active_record/associations.rb +40 -42
- data/lib/searchgasm/active_record/base.rb +75 -61
- data/lib/searchgasm/condition/base.rb +127 -0
- data/lib/searchgasm/condition/begins_with.rb +20 -0
- data/lib/searchgasm/condition/child_of.rb +11 -0
- data/lib/searchgasm/condition/contains.rb +20 -0
- data/lib/searchgasm/condition/descendant_of.rb +24 -0
- data/lib/searchgasm/condition/does_not_equal.rb +28 -0
- data/lib/searchgasm/condition/ends_with.rb +20 -0
- data/lib/searchgasm/condition/equals.rb +20 -0
- data/lib/searchgasm/condition/greater_than.rb +25 -0
- data/lib/searchgasm/condition/greater_than_or_equal_to.rb +20 -0
- data/lib/searchgasm/condition/inclusive_descendant_of.rb +13 -0
- data/lib/searchgasm/condition/keywords.rb +33 -0
- data/lib/searchgasm/condition/less_than.rb +25 -0
- data/lib/searchgasm/condition/less_than_or_equal_to.rb +20 -0
- data/lib/searchgasm/condition/sibling_of.rb +16 -0
- data/lib/searchgasm/condition/tree.rb +16 -0
- data/lib/searchgasm/conditions/base.rb +221 -0
- data/lib/searchgasm/conditions/protection.rb +30 -0
- data/lib/searchgasm/config.rb +137 -0
- data/lib/searchgasm/helpers/form_helper.rb +159 -0
- data/lib/searchgasm/helpers/search_helper.rb +178 -0
- data/lib/searchgasm/helpers/utilities_helper.rb +125 -0
- data/lib/searchgasm/search/base.rb +73 -179
- data/lib/searchgasm/search/conditions.rb +42 -166
- data/lib/searchgasm/search/ordering.rb +149 -0
- data/lib/searchgasm/search/pagination.rb +69 -0
- data/lib/searchgasm/search/protection.rb +61 -0
- data/lib/searchgasm/utilities.rb +30 -0
- data/lib/searchgasm/version.rb +44 -47
- data/lib/searchgasm.rb +57 -21
- data/searchgasm.gemspec +71 -46
- data/test/test_active_record_associations.rb +1 -1
- data/test/test_active_record_base.rb +4 -4
- data/test/test_condition.rb +143 -0
- data/test/{test_searchgasm_conditions.rb → test_conditions_base.rb} +43 -33
- data/test/test_search_base.rb +189 -0
- data/test/test_search_ordering.rb +91 -0
- data/test/test_search_pagination.rb +56 -0
- data/test/test_search_protection.rb +35 -0
- metadata +70 -45
- data/lib/searchgasm/search/condition.rb +0 -105
- data/lib/searchgasm/search/condition_types/begins_with_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/child_of_condition.rb +0 -17
- data/lib/searchgasm/search/condition_types/contains_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/descendant_of_condition.rb +0 -30
- data/lib/searchgasm/search/condition_types/does_not_equal_condition.rb +0 -34
- data/lib/searchgasm/search/condition_types/ends_with_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/equals_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/greater_than_condition.rb +0 -31
- data/lib/searchgasm/search/condition_types/greater_than_or_equal_to_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/inclusive_descendant_of_condition.rb +0 -19
- data/lib/searchgasm/search/condition_types/keywords_condition.rb +0 -39
- data/lib/searchgasm/search/condition_types/less_than_condition.rb +0 -31
- data/lib/searchgasm/search/condition_types/less_than_or_equal_to_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/sibling_of_condition.rb +0 -22
- data/lib/searchgasm/search/condition_types/tree_condition.rb +0 -20
- data/lib/searchgasm/search/utilities.rb +0 -34
- data/test/test_searchgasm_base.rb +0 -185
- data/test/test_searchgasm_condition_types.rb +0 -143
@@ -0,0 +1,221 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Conditions # :nodoc:
|
3
|
+
# = Conditions
|
4
|
+
#
|
5
|
+
# Represents a collection of conditions and performs various tasks on that collection. For information on each condition see Searchgasm::Condition.
|
6
|
+
# Each condition has its own file and class and the source for each condition is pretty self explanatory.
|
7
|
+
class Base
|
8
|
+
include Utilities
|
9
|
+
|
10
|
+
attr_accessor :klass, :relationship_name, :scope
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Registers a condition as an available condition for a column or a class.
|
14
|
+
#
|
15
|
+
# === Example
|
16
|
+
#
|
17
|
+
# config/initializers/searchgasm.rb
|
18
|
+
# # Actual function for MySQL databases only
|
19
|
+
# class SoundsLike < Searchgasm::Condition::Base
|
20
|
+
# class << self
|
21
|
+
# # I pass you the column, you tell me what you want the method to be called.
|
22
|
+
# # If you don't want to add this condition for that column, return nil
|
23
|
+
# # It defaults to "#{column.name}_sounds_like". So if thats what you want you don't even need to do this.
|
24
|
+
# def name_for_column(column)
|
25
|
+
# super
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # Only do this if you want aliases for your condition
|
29
|
+
# def aliases_for_column(column)
|
30
|
+
# ["#{column.name}_sounds", "#{column.name}_similar_to"]
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # You can return an array or a string. NOT a hash, because all of these conditions
|
35
|
+
# # need to eventually get merged together. The array or string can be anything you would put in
|
36
|
+
# # the :conditions option for ActiveRecord::Base.find()
|
37
|
+
# def to_conditions(value)
|
38
|
+
# ["#{quoted_table_name}.#{quoted_column_name} SOUNDS LIKE ?", value]
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# Searchgasm::Seearch::Conditions.register_condition(SoundsLikeCondition)
|
43
|
+
def register_condition(klass)
|
44
|
+
raise(ArgumentError, "You can only register conditions that extend Searchgasm::Condition::Base") unless klass.ancestors.include?(Searchgasm::Condition::Base)
|
45
|
+
conditions << klass unless conditions.include?(klass)
|
46
|
+
end
|
47
|
+
|
48
|
+
# A list of available condition type classes
|
49
|
+
def conditions
|
50
|
+
@@conditions ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def needed?(klass, conditions) # :nodoc:
|
54
|
+
if conditions.is_a?(Hash)
|
55
|
+
conditions.stringify_keys.keys.each do |condition|
|
56
|
+
return true unless klass.column_names.include?(condition)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(klass, init_conditions = {})
|
65
|
+
self.klass = klass
|
66
|
+
add_klass_conditions!
|
67
|
+
add_column_conditions!
|
68
|
+
add_associations!
|
69
|
+
self.conditions = init_conditions
|
70
|
+
end
|
71
|
+
|
72
|
+
# Setup methods for searching
|
73
|
+
[:all, :average, :calculate, :count, :find, :first, :maximum, :minimum, :sum].each do |method|
|
74
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
75
|
+
def #{method}(*args)
|
76
|
+
self.conditions = args.extract_options!
|
77
|
+
args << {:conditions => sanitize}
|
78
|
+
klass.#{method}(*args)
|
79
|
+
end
|
80
|
+
end_eval
|
81
|
+
end
|
82
|
+
|
83
|
+
# A list of includes to use when searching, includes relationships
|
84
|
+
def includes
|
85
|
+
i = []
|
86
|
+
associations.each do |association|
|
87
|
+
association_includes = association.includes
|
88
|
+
i << (association_includes.blank? ? association.relationship_name.to_sym : {association.relationship_name.to_sym => association_includes})
|
89
|
+
end
|
90
|
+
i.blank? ? nil : (i.size == 1 ? i.first : i)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sanitizes the conditions down into conditions that ActiveRecord::Base.find can understand.
|
94
|
+
def sanitize
|
95
|
+
conditions = merge_conditions(*objects.collect { |object| object.sanitize })
|
96
|
+
return scope if conditions.blank?
|
97
|
+
merge_conditions(conditions, scope)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Allows you to set the conditions via a hash. If you do not pass a hash it will set scope instead, so that you can continue to add conditions and ultimately
|
101
|
+
# merge it all together at the end.
|
102
|
+
def conditions=(conditions)
|
103
|
+
case conditions
|
104
|
+
when Hash
|
105
|
+
assert_valid_conditions(conditions)
|
106
|
+
remove_conditions_from_protected_assignement(conditions).each { |condition, value| send("#{condition}=", value) }
|
107
|
+
else
|
108
|
+
self.scope = conditions
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# All of the active conditions (conditions that have been set)
|
113
|
+
def conditions
|
114
|
+
conditions_hash = {}
|
115
|
+
objects.each do |object|
|
116
|
+
case object
|
117
|
+
when self.class
|
118
|
+
relationship_conditions = object.conditions
|
119
|
+
next if relationship_conditions.blank?
|
120
|
+
conditions_hash[object.relationship_name.to_sym] = relationship_conditions
|
121
|
+
else
|
122
|
+
next unless object.explicitly_set_value?
|
123
|
+
conditions_hash[object.name.to_sym] = object.value
|
124
|
+
end
|
125
|
+
end
|
126
|
+
conditions_hash
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
def add_associations!
|
131
|
+
klass.reflect_on_all_associations.each do |association|
|
132
|
+
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
133
|
+
def #{association.name}
|
134
|
+
if @#{association.name}.nil?
|
135
|
+
@#{association.name} = self.class.new(#{association.class_name})
|
136
|
+
@#{association.name}.relationship_name = "#{association.name}"
|
137
|
+
objects << @#{association.name}
|
138
|
+
end
|
139
|
+
@#{association.name}
|
140
|
+
end
|
141
|
+
|
142
|
+
def #{association.name}=(conditions); #{association.name}.conditions = conditions; end
|
143
|
+
def reset_#{association.name}!; objects.delete(#{association.name}); @#{association.name} = nil; end
|
144
|
+
end_eval
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_column_conditions!
|
149
|
+
klass.columns.each do |column|
|
150
|
+
self.class.conditions.each do |condition_klass|
|
151
|
+
name = condition_klass.name_for_column(column)
|
152
|
+
next if name.blank?
|
153
|
+
add_condition!(condition_klass, name, column)
|
154
|
+
condition_klass.aliases_for_column(column).each { |alias_name| add_condition_alias!(alias_name, name) }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def add_condition!(condition, name, column = nil)
|
160
|
+
condition_names << name
|
161
|
+
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
162
|
+
def #{name}_object
|
163
|
+
if @#{name}.nil?
|
164
|
+
@#{name} = #{condition.name}.new(klass#{column.nil? ? "" : ", \"#{column.name}\""})
|
165
|
+
objects << @#{name}
|
166
|
+
end
|
167
|
+
@#{name}
|
168
|
+
end
|
169
|
+
|
170
|
+
def #{name}; #{name}_object.value; end
|
171
|
+
def #{name}=(value); #{name}_object.value = value; end
|
172
|
+
def reset_#{name}!; objects.delete(#{name}_object); @#{name} = nil; end
|
173
|
+
end_eval
|
174
|
+
end
|
175
|
+
|
176
|
+
def add_condition_alias!(alias_name, name)
|
177
|
+
condition_names << alias_name
|
178
|
+
self.class.class_eval do
|
179
|
+
alias_method alias_name, name
|
180
|
+
alias_method "#{alias_name}=", "#{name}="
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def add_klass_conditions!
|
185
|
+
self.class.conditions.each do |condition|
|
186
|
+
name = condition.name_for_klass(klass)
|
187
|
+
next if name.blank?
|
188
|
+
add_condition!(condition, name)
|
189
|
+
condition.aliases_for_klass(klass).each { |alias_name| add_condition_alias!(alias_name, name) }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def assert_valid_conditions(conditions)
|
194
|
+
keys = condition_names.collect { |condition_name| condition_name.to_sym }
|
195
|
+
keys += klass.reflect_on_all_associations.collect { |association| association.name }
|
196
|
+
conditions.symbolize_keys.assert_valid_keys(keys)
|
197
|
+
end
|
198
|
+
|
199
|
+
def associations
|
200
|
+
objects.select { |object| object.is_a?(self.class) }
|
201
|
+
end
|
202
|
+
|
203
|
+
def condition_names
|
204
|
+
@condition_names ||= []
|
205
|
+
end
|
206
|
+
|
207
|
+
def objects
|
208
|
+
@objects ||= []
|
209
|
+
end
|
210
|
+
|
211
|
+
def remove_conditions_from_protected_assignement(conditions)
|
212
|
+
return conditions if klass.accessible_conditions.nil? && klass.protected_conditions.nil?
|
213
|
+
if klass.accessible_conditions
|
214
|
+
conditions.reject { |condition, value| !klass.accessible_conditions.include?(condition.to_s) }
|
215
|
+
elsif klass.protected_conditions
|
216
|
+
conditions.reject { |condition, value| klass.protected_conditions.include?(condition.to_s) }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Conditions
|
3
|
+
# = Conditions Protection
|
4
|
+
#
|
5
|
+
# Adds protection from SQL injections. Just set protect = true and it will limit what kind of conditions it will accept.
|
6
|
+
module Protection
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
attr_accessor :protect
|
10
|
+
alias_method_chain :conditions=, :protection
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def conditions_with_protection=(conditions)
|
15
|
+
unless conditions.is_a?(Hash)
|
16
|
+
if protect?
|
17
|
+
return if conditions.blank?
|
18
|
+
raise(ArgumentError, "You can not set a scope or pass SQL while the search is being protected")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
self.conditions_without_protection = conditions
|
23
|
+
end
|
24
|
+
|
25
|
+
def protect?
|
26
|
+
protect == true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
# = Config
|
3
|
+
# Adds default configuration for all of searchgasm. Just make sure you set your config before you use Searchgasm.
|
4
|
+
# For rails the best place to do this is in config/initializers. Create a file in there called searchgasm.rb with the following content:
|
5
|
+
#
|
6
|
+
# === Example
|
7
|
+
#
|
8
|
+
# # config/iniitializers/searchgasm.rb
|
9
|
+
# Searchgasm::Config.configure do |config|
|
10
|
+
# config.you_option_here = your_value # see methods below
|
11
|
+
# end
|
12
|
+
class Config
|
13
|
+
class << self
|
14
|
+
# Convenience method for setting configuration
|
15
|
+
# See example at top of class.
|
16
|
+
def configure
|
17
|
+
yield self
|
18
|
+
end
|
19
|
+
|
20
|
+
def asc_indicator # :nodoc:
|
21
|
+
@asc_indicator ||= " ▲"
|
22
|
+
end
|
23
|
+
|
24
|
+
# The indicator that is used when the sort of a column is ascending
|
25
|
+
#
|
26
|
+
# * <tt>Default:</tt> ▲
|
27
|
+
# * <tt>Accepts:</tt> String or a Proc.
|
28
|
+
#
|
29
|
+
# === Examples
|
30
|
+
#
|
31
|
+
# config.asc_indicator = "(ASC)"
|
32
|
+
# config.asc_indicator = Proc.new { |template| template.image_tag("asc.jpg") }
|
33
|
+
def asc_indicator=(value)
|
34
|
+
@asc_indicator = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def desc_indicator # :nodoc:
|
38
|
+
@desc_indicator ||= " ▼"
|
39
|
+
end
|
40
|
+
|
41
|
+
# See asc_indicator=
|
42
|
+
def desc_indicator=(value)
|
43
|
+
@desc_indicator = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def pages_type # :nodoc:
|
47
|
+
@pages_type ||= :select
|
48
|
+
end
|
49
|
+
|
50
|
+
# The default value for the :type option in the pages helper.
|
51
|
+
#
|
52
|
+
# * <tt>Default:</tt> :select
|
53
|
+
# * <tt>Accepts:</tt> :select, :links
|
54
|
+
def pages_type=(value)
|
55
|
+
@pages_type = value.to_sym
|
56
|
+
end
|
57
|
+
|
58
|
+
def per_page_choices # :nodoc:
|
59
|
+
@per_page_choices ||= [10, 25, 50, 100, 150, 200, nil]
|
60
|
+
end
|
61
|
+
|
62
|
+
# The choices used in the per_page helper
|
63
|
+
#
|
64
|
+
# * <tt>Default:</tt> [10, 25, 50, 100, 150, 200, nil]
|
65
|
+
# * <tt>Accepts:</tt> Array
|
66
|
+
#
|
67
|
+
# nil means "Show all"
|
68
|
+
def per_page_choices=(value)
|
69
|
+
@per_page_choices = value
|
70
|
+
end
|
71
|
+
|
72
|
+
def per_page_type # :nodoc:
|
73
|
+
@per_page_type ||= :select
|
74
|
+
end
|
75
|
+
|
76
|
+
# The default value for the :type option in the per_page helper.
|
77
|
+
#
|
78
|
+
# * <tt>Default:</tt> :select
|
79
|
+
# * <tt>Accepts:</tt> :select, :links
|
80
|
+
def per_page_type=(value)
|
81
|
+
@per_page_type = value.to_sym
|
82
|
+
end
|
83
|
+
|
84
|
+
def hidden_fields # :nodoc:
|
85
|
+
@hidden_fields ||= (Search::Base::SPECIAL_FIND_OPTIONS - [:page])
|
86
|
+
end
|
87
|
+
|
88
|
+
# Which hidden fields to automatically include when creating a form with a Searchgasm object. See Searchgasm::Helpers::FormHelper for more info.
|
89
|
+
#
|
90
|
+
# * <tt>Default:</tt> [:order_by, :order_as, :per_page]
|
91
|
+
# * <tt>Accepts:</tt> Array, nil, false
|
92
|
+
def hidden_fields=(value)
|
93
|
+
@hidden_fields = value
|
94
|
+
end
|
95
|
+
|
96
|
+
def remote_helpers # :nodoc:
|
97
|
+
@remote_helpers ||= false
|
98
|
+
end
|
99
|
+
|
100
|
+
# Tells all helpers to default to using remote links (AJAX) instead of normal links.
|
101
|
+
#
|
102
|
+
# * <tt>Default:</tt> false
|
103
|
+
# * <tt>Accepts:</tt> Boolean
|
104
|
+
#
|
105
|
+
# nil means "Show all"
|
106
|
+
def remote_helpers=(value)
|
107
|
+
@remote_helpers = value
|
108
|
+
end
|
109
|
+
|
110
|
+
def remote_helpers? # :nodoc:
|
111
|
+
remote_helpers == true
|
112
|
+
end
|
113
|
+
|
114
|
+
def search_scope # :nodoc:
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def search_obj_name # :nodoc:
|
119
|
+
@search_obj_name ||= :@search
|
120
|
+
end
|
121
|
+
|
122
|
+
# The instance variable name you use to assign your search to. This allows the helpers to grab your Searchgasm object without having
|
123
|
+
# to specify it everywhere.
|
124
|
+
#
|
125
|
+
# * <tt>Default:</tt> :@search
|
126
|
+
# * <tt>Accepts:</tt> String or Symbol.
|
127
|
+
#
|
128
|
+
# === Examples
|
129
|
+
#
|
130
|
+
# config.search_obj_name = :@search
|
131
|
+
# config.search_obj_name = "@search"
|
132
|
+
def search_obj_name=(value)
|
133
|
+
@search_obj_name = value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Helpers
|
3
|
+
# = Form Helper
|
4
|
+
#
|
5
|
+
# Enables you to use form_for and fields_for just like you do with an ActiveRecord object.
|
6
|
+
#
|
7
|
+
# === Examples
|
8
|
+
#
|
9
|
+
# Let's assume @search is searching Address
|
10
|
+
#
|
11
|
+
# form_for(@search) # is equivalent to form_for(:search, @search, :url => addresses_path)
|
12
|
+
# form_for([@current_user, @search]) # is equivalent to form_for(:search, @search, :url => user_addresses_path(@current_user))
|
13
|
+
# form_for([:admin, @search]) # is equivalent to form_for(:search, @search, :url => admin_addresses_path)
|
14
|
+
# form_for(:search, @search, :url => whatever_path)
|
15
|
+
#
|
16
|
+
# The goal was to mimic ActiveRecord. You can also pass a Searchgasm::Conditions::Base object as well and it will function the same way.
|
17
|
+
#
|
18
|
+
# === Automatic hidden fields generation
|
19
|
+
#
|
20
|
+
# If you pass a Searchgasm::Search::Base object it automatically adds the :order_by, :order_as, and :per_page hidden fields. This is done so that when someone
|
21
|
+
# creates a new search, their options are remembered. It keeps the search consisten and is much more user friendly. If you want to override this you can pass the
|
22
|
+
# following options. Or you can set this up in your configuration, see Searchgasm::Config for more details.
|
23
|
+
#
|
24
|
+
# === Options
|
25
|
+
#
|
26
|
+
# * <tt>:hidden_fields</tt> --- Array, a list of hidden fields to include. Defaults to [:order_by, :order_as, :per_page]. Pass false, nil, or a blank array to not include any.
|
27
|
+
module FormHelper
|
28
|
+
module Shared # :nodoc:
|
29
|
+
private
|
30
|
+
def searchgasm_object?(object)
|
31
|
+
object.is_a?(Search::Base) || object.is_a?(Conditions::Base)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_searchgasm_object(args)
|
35
|
+
case args.first
|
36
|
+
when String, Symbol
|
37
|
+
search_object = searchgasm_object?(args[1]) ? args[1] : instance_variable_get("@#{args.first}")
|
38
|
+
when Array
|
39
|
+
search_object = args.first.last
|
40
|
+
else
|
41
|
+
search_object = args.first
|
42
|
+
end
|
43
|
+
|
44
|
+
searchgasm_object?(search_object) ? search_object : nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def searchgasm_args(args, search_object, for_helper = nil)
|
48
|
+
args = args.dup
|
49
|
+
first = args.shift
|
50
|
+
|
51
|
+
# Setup args
|
52
|
+
case first
|
53
|
+
when String, Symbol
|
54
|
+
args.unshift(search_object).unshift(first)
|
55
|
+
else
|
56
|
+
name = search_object.is_a?(Conditions::Base) ? (search_object.relationship_name || :conditions) : :search
|
57
|
+
args.unshift(search_object).unshift(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
if for_helper != :fields_for
|
61
|
+
options = args.extract_options!
|
62
|
+
options[:html] ||= {}
|
63
|
+
options[:html][:method] ||= :get
|
64
|
+
options[:method] ||= options[:html][:method] if for_helper == :remote_form_for
|
65
|
+
options[:html][:id] ||= searchgasm_form_id(search_object)
|
66
|
+
|
67
|
+
# Setup options
|
68
|
+
case first
|
69
|
+
when Array
|
70
|
+
first.pop
|
71
|
+
first << search_object.klass.new
|
72
|
+
options[:url] ||= polymorphic_path(first)
|
73
|
+
else
|
74
|
+
options[:url] ||= polymorphic_path(search_object.klass.new)
|
75
|
+
end
|
76
|
+
|
77
|
+
args << options
|
78
|
+
end
|
79
|
+
|
80
|
+
args
|
81
|
+
end
|
82
|
+
|
83
|
+
def insert_searchgasm_fields(args, search_object)
|
84
|
+
return unless search_object.is_a?(Search::Base)
|
85
|
+
name = args.first
|
86
|
+
options = args.extract_options!
|
87
|
+
(options.delete(:hidden_fields) || Config.hidden_fields).each do |option|
|
88
|
+
concat(hidden_field(name, option, :object => search_object, :value => (option == :order_by ? searchgasm_order_by_value(search_object.order_by) : search_object.send(option))))
|
89
|
+
end
|
90
|
+
args << options
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module Base # :nodoc:
|
95
|
+
include Shared
|
96
|
+
|
97
|
+
def fields_for_with_searchgasm(*args, &block)
|
98
|
+
search_object = find_searchgasm_object(args)
|
99
|
+
if search_object
|
100
|
+
new_args = searchgasm_args(args, search_object, :fields_for)
|
101
|
+
insert_searchgasm_fields(new_args, search_object)
|
102
|
+
fields_for_without_searchgasm(*new_args, &block)
|
103
|
+
else
|
104
|
+
fields_for_without_searchgasm(*args, &block)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def form_for_with_searchgasm(*args, &block)
|
109
|
+
search_object = find_searchgasm_object(args)
|
110
|
+
if search_object
|
111
|
+
form_for_without_searchgasm(*searchgasm_args(args, search_object, :form_for), &block)
|
112
|
+
else
|
113
|
+
form_for_without_searchgasm(*args, &block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def remote_form_for_with_searchgasm(*args, &block)
|
118
|
+
search_object = find_searchgasm_object(args)
|
119
|
+
if search_object
|
120
|
+
remote_form_for_without_searchgasm(*searchgasm_args(args, search_object, :remote_form_for), &block)
|
121
|
+
else
|
122
|
+
remote_form_for_without_searchgasm(*args, &block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
module FormBuilder # :nodoc:
|
128
|
+
include Shared
|
129
|
+
|
130
|
+
def fields_for_with_searchgasm(*args, &block)
|
131
|
+
search_object = find_searchgasm_object(args)
|
132
|
+
if search_object
|
133
|
+
new_args = searchgasm_args(args, search_object, :fields_for)
|
134
|
+
insert_searchgasm_fields(new_args, search_object)
|
135
|
+
fields_for_without_searchgasm(*new_args, &block)
|
136
|
+
else
|
137
|
+
fields_for_without_searchgasm(*args, &block)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if defined?(ActionView)
|
146
|
+
ActionView::Base.send(:include, Searchgasm::Helpers::FormHelper::Base)
|
147
|
+
|
148
|
+
ActionView::Base.class_eval do
|
149
|
+
alias_method_chain :fields_for, :searchgasm
|
150
|
+
alias_method_chain :form_for, :searchgasm
|
151
|
+
alias_method_chain :remote_form_for, :searchgasm
|
152
|
+
end
|
153
|
+
|
154
|
+
ActionView::Helpers::FormBuilder.send(:include, Searchgasm::Helpers::FormHelper::FormBuilder)
|
155
|
+
|
156
|
+
ActionView::Helpers::FormBuilder.class_eval do
|
157
|
+
alias_method_chain :fields_for, :searchgasm
|
158
|
+
end
|
159
|
+
end
|