searchgasm 0.9.6 → 0.9.7
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 +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
|