activerecord 1.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (178) hide show
  1. data/CHANGELOG +5518 -76
  2. data/README.rdoc +222 -0
  3. data/examples/performance.rb +162 -0
  4. data/examples/simple.rb +14 -0
  5. data/lib/active_record/aggregations.rb +192 -80
  6. data/lib/active_record/association_preload.rb +403 -0
  7. data/lib/active_record/associations/association_collection.rb +545 -53
  8. data/lib/active_record/associations/association_proxy.rb +295 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +91 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +78 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +127 -36
  12. data/lib/active_record/associations/has_many_association.rb +108 -84
  13. data/lib/active_record/associations/has_many_through_association.rb +116 -0
  14. data/lib/active_record/associations/has_one_association.rb +143 -0
  15. data/lib/active_record/associations/has_one_through_association.rb +40 -0
  16. data/lib/active_record/associations/through_association_scope.rb +154 -0
  17. data/lib/active_record/associations.rb +2086 -368
  18. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +95 -0
  20. data/lib/active_record/attribute_methods/primary_key.rb +50 -0
  21. data/lib/active_record/attribute_methods/query.rb +39 -0
  22. data/lib/active_record/attribute_methods/read.rb +116 -0
  23. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -0
  24. data/lib/active_record/attribute_methods/write.rb +37 -0
  25. data/lib/active_record/attribute_methods.rb +60 -0
  26. data/lib/active_record/autosave_association.rb +369 -0
  27. data/lib/active_record/base.rb +1603 -721
  28. data/lib/active_record/callbacks.rb +176 -225
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +365 -0
  30. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
  31. data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
  32. data/lib/active_record/connection_adapters/abstract/database_statements.rb +329 -0
  33. data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
  34. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -0
  35. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
  36. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +543 -0
  37. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -279
  38. data/lib/active_record/connection_adapters/mysql_adapter.rb +594 -82
  39. data/lib/active_record/connection_adapters/postgresql_adapter.rb +988 -135
  40. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -0
  41. data/lib/active_record/connection_adapters/sqlite_adapter.rb +365 -71
  42. data/lib/active_record/counter_cache.rb +115 -0
  43. data/lib/active_record/dynamic_finder_match.rb +53 -0
  44. data/lib/active_record/dynamic_scope_match.rb +32 -0
  45. data/lib/active_record/errors.rb +172 -0
  46. data/lib/active_record/fixtures.rb +941 -105
  47. data/lib/active_record/locale/en.yml +40 -0
  48. data/lib/active_record/locking/optimistic.rb +172 -0
  49. data/lib/active_record/locking/pessimistic.rb +55 -0
  50. data/lib/active_record/log_subscriber.rb +48 -0
  51. data/lib/active_record/migration.rb +617 -0
  52. data/lib/active_record/named_scope.rb +138 -0
  53. data/lib/active_record/nested_attributes.rb +417 -0
  54. data/lib/active_record/observer.rb +105 -36
  55. data/lib/active_record/persistence.rb +291 -0
  56. data/lib/active_record/query_cache.rb +36 -0
  57. data/lib/active_record/railtie.rb +91 -0
  58. data/lib/active_record/railties/controller_runtime.rb +38 -0
  59. data/lib/active_record/railties/databases.rake +512 -0
  60. data/lib/active_record/reflection.rb +364 -87
  61. data/lib/active_record/relation/batches.rb +89 -0
  62. data/lib/active_record/relation/calculations.rb +286 -0
  63. data/lib/active_record/relation/finder_methods.rb +355 -0
  64. data/lib/active_record/relation/predicate_builder.rb +41 -0
  65. data/lib/active_record/relation/query_methods.rb +261 -0
  66. data/lib/active_record/relation/spawn_methods.rb +112 -0
  67. data/lib/active_record/relation.rb +393 -0
  68. data/lib/active_record/schema.rb +59 -0
  69. data/lib/active_record/schema_dumper.rb +195 -0
  70. data/lib/active_record/serialization.rb +60 -0
  71. data/lib/active_record/serializers/xml_serializer.rb +244 -0
  72. data/lib/active_record/session_store.rb +340 -0
  73. data/lib/active_record/test_case.rb +67 -0
  74. data/lib/active_record/timestamp.rb +88 -0
  75. data/lib/active_record/transactions.rb +329 -75
  76. data/lib/active_record/validations/associated.rb +48 -0
  77. data/lib/active_record/validations/uniqueness.rb +185 -0
  78. data/lib/active_record/validations.rb +58 -179
  79. data/lib/active_record/version.rb +9 -0
  80. data/lib/active_record.rb +100 -24
  81. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  82. data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
  83. data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
  84. data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
  85. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  86. data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
  87. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  88. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  89. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  90. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
  91. data/lib/rails/generators/active_record.rb +27 -0
  92. metadata +216 -158
  93. data/README +0 -361
  94. data/RUNNING_UNIT_TESTS +0 -36
  95. data/dev-utils/eval_debugger.rb +0 -9
  96. data/examples/associations.rb +0 -87
  97. data/examples/shared_setup.rb +0 -15
  98. data/examples/validation.rb +0 -88
  99. data/install.rb +0 -60
  100. data/lib/active_record/deprecated_associations.rb +0 -70
  101. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  102. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  103. data/lib/active_record/support/clean_logger.rb +0 -10
  104. data/lib/active_record/support/inflector.rb +0 -70
  105. data/lib/active_record/vendor/mysql.rb +0 -1117
  106. data/lib/active_record/vendor/simple.rb +0 -702
  107. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  108. data/lib/active_record/wrappings.rb +0 -59
  109. data/rakefile +0 -122
  110. data/test/abstract_unit.rb +0 -16
  111. data/test/aggregations_test.rb +0 -34
  112. data/test/all.sh +0 -8
  113. data/test/associations_test.rb +0 -477
  114. data/test/base_test.rb +0 -513
  115. data/test/class_inheritable_attributes_test.rb +0 -33
  116. data/test/connections/native_mysql/connection.rb +0 -24
  117. data/test/connections/native_postgresql/connection.rb +0 -24
  118. data/test/connections/native_sqlite/connection.rb +0 -24
  119. data/test/deprecated_associations_test.rb +0 -336
  120. data/test/finder_test.rb +0 -67
  121. data/test/fixtures/accounts/signals37 +0 -3
  122. data/test/fixtures/accounts/unknown +0 -2
  123. data/test/fixtures/auto_id.rb +0 -4
  124. data/test/fixtures/column_name.rb +0 -3
  125. data/test/fixtures/companies/first_client +0 -6
  126. data/test/fixtures/companies/first_firm +0 -4
  127. data/test/fixtures/companies/second_client +0 -6
  128. data/test/fixtures/company.rb +0 -37
  129. data/test/fixtures/company_in_module.rb +0 -33
  130. data/test/fixtures/course.rb +0 -3
  131. data/test/fixtures/courses/java +0 -2
  132. data/test/fixtures/courses/ruby +0 -2
  133. data/test/fixtures/customer.rb +0 -30
  134. data/test/fixtures/customers/david +0 -6
  135. data/test/fixtures/db_definitions/mysql.sql +0 -96
  136. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  137. data/test/fixtures/db_definitions/postgresql.sql +0 -113
  138. data/test/fixtures/db_definitions/postgresql2.sql +0 -4
  139. data/test/fixtures/db_definitions/sqlite.sql +0 -85
  140. data/test/fixtures/db_definitions/sqlite2.sql +0 -4
  141. data/test/fixtures/default.rb +0 -2
  142. data/test/fixtures/developer.rb +0 -8
  143. data/test/fixtures/developers/david +0 -2
  144. data/test/fixtures/developers/jamis +0 -2
  145. data/test/fixtures/developers_projects/david_action_controller +0 -2
  146. data/test/fixtures/developers_projects/david_active_record +0 -2
  147. data/test/fixtures/developers_projects/jamis_active_record +0 -2
  148. data/test/fixtures/entrant.rb +0 -3
  149. data/test/fixtures/entrants/first +0 -3
  150. data/test/fixtures/entrants/second +0 -3
  151. data/test/fixtures/entrants/third +0 -3
  152. data/test/fixtures/fixture_database.sqlite +0 -0
  153. data/test/fixtures/fixture_database_2.sqlite +0 -0
  154. data/test/fixtures/movie.rb +0 -5
  155. data/test/fixtures/movies/first +0 -2
  156. data/test/fixtures/movies/second +0 -2
  157. data/test/fixtures/project.rb +0 -3
  158. data/test/fixtures/projects/action_controller +0 -2
  159. data/test/fixtures/projects/active_record +0 -2
  160. data/test/fixtures/reply.rb +0 -21
  161. data/test/fixtures/subscriber.rb +0 -5
  162. data/test/fixtures/subscribers/first +0 -2
  163. data/test/fixtures/subscribers/second +0 -2
  164. data/test/fixtures/topic.rb +0 -20
  165. data/test/fixtures/topics/first +0 -9
  166. data/test/fixtures/topics/second +0 -8
  167. data/test/fixtures_test.rb +0 -20
  168. data/test/inflector_test.rb +0 -104
  169. data/test/inheritance_test.rb +0 -125
  170. data/test/lifecycle_test.rb +0 -110
  171. data/test/modules_test.rb +0 -21
  172. data/test/multiple_db_test.rb +0 -46
  173. data/test/pk_test.rb +0 -57
  174. data/test/reflection_test.rb +0 -78
  175. data/test/thread_safety_test.rb +0 -33
  176. data/test/transactions_test.rb +0 -83
  177. data/test/unconnected_test.rb +0 -24
  178. data/test/validations_test.rb +0 -126
@@ -0,0 +1,261 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+ require 'active_support/core_ext/object/blank'
3
+
4
+ module ActiveRecord
5
+ module QueryMethods
6
+ extend ActiveSupport::Concern
7
+
8
+ attr_accessor :includes_values, :eager_load_values, :preload_values,
9
+ :select_values, :group_values, :order_values, :joins_values, :where_values, :having_values,
10
+ :limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, :from_value
11
+
12
+ def includes(*args)
13
+ args.reject! { |a| a.blank? }
14
+ clone.tap {|r| r.includes_values = (r.includes_values + args).flatten.uniq if args.present? }
15
+ end
16
+
17
+ def eager_load(*args)
18
+ clone.tap {|r| r.eager_load_values += args if args.present? }
19
+ end
20
+
21
+ def preload(*args)
22
+ clone.tap {|r| r.preload_values += args if args.present? }
23
+ end
24
+
25
+ def select(*args)
26
+ if block_given?
27
+ to_a.select {|*block_args| yield(*block_args) }
28
+ else
29
+ clone.tap {|r| r.select_values += args if args.present? }
30
+ end
31
+ end
32
+
33
+ def group(*args)
34
+ clone.tap {|r| r.group_values += args.flatten if args.present? }
35
+ end
36
+
37
+ def order(*args)
38
+ clone.tap {|r| r.order_values += args if args.present? }
39
+ end
40
+
41
+ def reorder(*args)
42
+ clone.tap {|r| r.order_values = args if args.present? }
43
+ end
44
+
45
+ def joins(*args)
46
+ args.flatten!
47
+ clone.tap {|r| r.joins_values += args if args.present? }
48
+ end
49
+
50
+ def where(opts, *rest)
51
+ value = build_where(opts, rest)
52
+ copy = clone
53
+ copy.where_values += Array.wrap(value) if value
54
+ copy
55
+ end
56
+
57
+ def having(*args)
58
+ value = build_where(*args)
59
+ clone.tap {|r| r.having_values += Array.wrap(value) if value.present? }
60
+ end
61
+
62
+ def limit(value = true)
63
+ copy = clone
64
+ copy.limit_value = value
65
+ copy
66
+ end
67
+
68
+ def offset(value = true)
69
+ clone.tap {|r| r.offset_value = value }
70
+ end
71
+
72
+ def lock(locks = true)
73
+ case locks
74
+ when String, TrueClass, NilClass
75
+ clone.tap {|r| r.lock_value = locks || true }
76
+ else
77
+ clone.tap {|r| r.lock_value = false }
78
+ end
79
+ end
80
+
81
+ def readonly(value = true)
82
+ clone.tap {|r| r.readonly_value = value }
83
+ end
84
+
85
+ def create_with(value = true)
86
+ clone.tap {|r| r.create_with_value = value }
87
+ end
88
+
89
+ def from(value = true)
90
+ clone.tap {|r| r.from_value = value }
91
+ end
92
+
93
+ def extending(*modules, &block)
94
+ modules << Module.new(&block) if block_given?
95
+ clone.tap {|r| r.send(:apply_modules, *modules) }
96
+ end
97
+
98
+ def reverse_order
99
+ order_clause = arel.order_clauses.join(', ')
100
+ relation = except(:order)
101
+
102
+ order = order_clause.blank? ?
103
+ "#{@klass.table_name}.#{@klass.primary_key} DESC" :
104
+ reverse_sql_order(order_clause)
105
+
106
+ relation.order Arel::SqlLiteral.new order
107
+ end
108
+
109
+ def arel
110
+ @arel ||= build_arel
111
+ end
112
+
113
+ def custom_join_sql(*joins)
114
+ arel = table
115
+ joins.each do |join|
116
+ next if join.blank?
117
+
118
+ @implicit_readonly = true
119
+
120
+ case join
121
+ when Hash, Array, Symbol
122
+ if array_of_strings?(join)
123
+ join_string = join.join(' ')
124
+ arel = arel.join(Arel::SqlLiteral.new(join_string))
125
+ end
126
+ when String
127
+ arel = arel.join(Arel::SqlLiteral.new(join))
128
+ else
129
+ arel = arel.join(join)
130
+ end
131
+ end
132
+ arel.joins(arel)
133
+ end
134
+
135
+ def build_arel
136
+ arel = table
137
+
138
+ arel = build_joins(arel, @joins_values) unless @joins_values.empty?
139
+
140
+ (@where_values - ['']).uniq.each do |where|
141
+ case where
142
+ when Arel::SqlLiteral
143
+ arel = arel.where(where)
144
+ else
145
+ sql = where.is_a?(String) ? where : where.to_sql
146
+ arel = arel.where(Arel::SqlLiteral.new("(#{sql})"))
147
+ end
148
+ end
149
+
150
+ arel = arel.having(*@having_values.uniq.select{|h| h.present?}) unless @having_values.empty?
151
+
152
+ arel = arel.take(@limit_value) if @limit_value
153
+ arel = arel.skip(@offset_value) if @offset_value
154
+
155
+ arel = arel.group(*@group_values.uniq.select{|g| g.present?}) unless @group_values.empty?
156
+
157
+ arel = arel.order(*@order_values.uniq.select{|o| o.present?}) unless @order_values.empty?
158
+
159
+ arel = build_select(arel, @select_values.uniq)
160
+
161
+ arel = arel.from(@from_value) if @from_value
162
+ arel = arel.lock(@lock_value) if @lock_value
163
+
164
+ arel
165
+ end
166
+
167
+ def build_where(opts, other = [])
168
+ case opts
169
+ when String, Array
170
+ @klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))
171
+ when Hash
172
+ attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
173
+ PredicateBuilder.new(table.engine).build_from_hash(attributes, table)
174
+ else
175
+ opts
176
+ end
177
+ end
178
+
179
+ private
180
+
181
+ def build_joins(relation, joins)
182
+ joined_associations = []
183
+ association_joins = []
184
+
185
+ joins = @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
186
+
187
+ joins.each do |join|
188
+ association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join)
189
+ end
190
+
191
+ stashed_association_joins = joins.grep(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)
192
+
193
+ non_association_joins = (joins - association_joins - stashed_association_joins)
194
+ custom_joins = custom_join_sql(*non_association_joins)
195
+
196
+ join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
197
+
198
+ join_dependency.graft(*stashed_association_joins)
199
+
200
+ @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
201
+
202
+ to_join = []
203
+
204
+ join_dependency.join_associations.each do |association|
205
+ if (association_relation = association.relation).is_a?(Array)
206
+ to_join << [association_relation.first, association.join_class, association.association_join.first]
207
+ to_join << [association_relation.last, association.join_class, association.association_join.last]
208
+ else
209
+ to_join << [association_relation, association.join_class, association.association_join]
210
+ end
211
+ end
212
+
213
+ to_join.each do |tj|
214
+ unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
215
+ joined_associations << tj
216
+ relation = relation.join(tj[0], tj[1]).on(*tj[2])
217
+ end
218
+ end
219
+
220
+ relation.join(custom_joins)
221
+ end
222
+
223
+ def build_select(arel, selects)
224
+ unless selects.empty?
225
+ @implicit_readonly = false
226
+ # TODO: fix this ugly hack, we should refactor the callers to get an ARel compatible array.
227
+ # Before this change we were passing to ARel the last element only, and ARel is capable of handling an array
228
+ if selects.all? {|s| s.is_a?(String) || !s.is_a?(Arel::Expression) } && !(selects.last =~ /^COUNT\(/)
229
+ arel.project(*selects)
230
+ else
231
+ arel.project(selects.last)
232
+ end
233
+ else
234
+ arel.project(Arel::SqlLiteral.new(@klass.quoted_table_name + '.*'))
235
+ end
236
+ end
237
+
238
+ def apply_modules(modules)
239
+ values = Array.wrap(modules)
240
+ @extensions += values if values.present?
241
+ values.each {|extension| extend(extension) }
242
+ end
243
+
244
+ def reverse_sql_order(order_query)
245
+ order_query.to_s.split(/,/).each { |s|
246
+ if s.match(/\s(asc|ASC)$/)
247
+ s.gsub!(/\s(asc|ASC)$/, ' DESC')
248
+ elsif s.match(/\s(desc|DESC)$/)
249
+ s.gsub!(/\s(desc|DESC)$/, ' ASC')
250
+ else
251
+ s.concat(' DESC')
252
+ end
253
+ }.join(',')
254
+ end
255
+
256
+ def array_of_strings?(o)
257
+ o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
258
+ end
259
+
260
+ end
261
+ end
@@ -0,0 +1,112 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
3
+ module ActiveRecord
4
+ module SpawnMethods
5
+ def merge(r)
6
+ merged_relation = clone
7
+ return merged_relation unless r
8
+
9
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - [:joins, :where]).each do |method|
10
+ value = r.send(:"#{method}_values")
11
+ unless value.empty?
12
+ if method == :includes
13
+ merged_relation = merged_relation.includes(value)
14
+ else
15
+ merged_relation.send(:"#{method}_values=", value)
16
+ end
17
+ end
18
+ end
19
+
20
+ merged_relation = merged_relation.joins(r.joins_values)
21
+
22
+ merged_wheres = @where_values
23
+
24
+ r.where_values.each do |w|
25
+ if w.respond_to?(:operator) && w.operator == :==
26
+ merged_wheres = merged_wheres.reject { |p|
27
+ p.respond_to?(:operator) && p.operator == :== && p.operand1.name == w.operand1.name
28
+ }
29
+ end
30
+
31
+ merged_wheres += [w]
32
+ end
33
+
34
+ merged_relation.where_values = merged_wheres
35
+
36
+ Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
37
+ unless (value = r.send(:"#{method}_value")).nil?
38
+ merged_relation.send(:"#{method}_value=", value)
39
+ end
40
+ end
41
+
42
+ merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
43
+
44
+ # Apply scope extension modules
45
+ merged_relation.send :apply_modules, r.extensions
46
+
47
+ merged_relation
48
+ end
49
+
50
+ alias :& :merge
51
+
52
+ def except(*skips)
53
+ result = self.class.new(@klass, table)
54
+
55
+ (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |method|
56
+ result.send(:"#{method}_values=", send(:"#{method}_values")) unless skips.include?(method)
57
+ end
58
+
59
+ Relation::SINGLE_VALUE_METHODS.each do |method|
60
+ result.send(:"#{method}_value=", send(:"#{method}_value")) unless skips.include?(method)
61
+ end
62
+
63
+ result
64
+ end
65
+
66
+ def only(*onlies)
67
+ result = self.class.new(@klass, table)
68
+
69
+ onlies.each do |only|
70
+ if (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).include?(only)
71
+ result.send(:"#{only}_values=", send(:"#{only}_values"))
72
+ elsif Relation::SINGLE_VALUE_METHODS.include?(only)
73
+ result.send(:"#{only}_value=", send(:"#{only}_value"))
74
+ else
75
+ raise "Invalid argument : #{only}"
76
+ end
77
+ end
78
+
79
+ result
80
+ end
81
+
82
+ VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
83
+ :order, :select, :readonly, :group, :having, :from, :lock ]
84
+
85
+ def apply_finder_options(options)
86
+ relation = clone
87
+ return relation unless options
88
+
89
+ options.assert_valid_keys(VALID_FIND_OPTIONS)
90
+
91
+ [:joins, :select, :group, :having, :limit, :offset, :from, :lock].each do |finder|
92
+ if value = options[finder]
93
+ relation = relation.send(finder, value)
94
+ end
95
+ end
96
+
97
+ relation = relation.readonly(options[:readonly]) if options.key? :readonly
98
+
99
+ # Give precedence to newly-applied orders and groups to play nicely with with_scope
100
+ [:group, :order].each do |finder|
101
+ relation.send("#{finder}_values=", Array.wrap(options[finder]) + relation.send("#{finder}_values")) if options.has_key?(finder)
102
+ end
103
+
104
+ relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
105
+ relation = relation.includes(options[:include]) if options.has_key?(:include)
106
+ relation = relation.extending(options[:extend]) if options.has_key?(:extend)
107
+
108
+ relation
109
+ end
110
+
111
+ end
112
+ end