activerecord 4.0.13 → 4.1.0.beta1

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -1,8 +1,35 @@
1
- require 'thread'
2
- require 'thread_safe'
1
+ require 'set'
2
+ require 'active_support/concern'
3
+ require 'active_support/deprecation'
3
4
 
4
5
  module ActiveRecord
5
6
  module Delegation # :nodoc:
7
+ module DelegateCache
8
+ def relation_delegate_class(klass) # :nodoc:
9
+ @relation_delegate_cache[klass]
10
+ end
11
+
12
+ def initialize_relation_delegate_cache # :nodoc:
13
+ @relation_delegate_cache = cache = {}
14
+ [
15
+ ActiveRecord::Relation,
16
+ ActiveRecord::Associations::CollectionProxy,
17
+ ActiveRecord::AssociationRelation
18
+ ].each do |klass|
19
+ delegate = Class.new(klass) {
20
+ include ClassSpecificRelation
21
+ }
22
+ const_set klass.name.gsub('::', '_'), delegate
23
+ cache[klass] = delegate
24
+ end
25
+ end
26
+
27
+ def inherited(child_class)
28
+ child_class.initialize_relation_delegate_cache
29
+ super
30
+ end
31
+ end
32
+
6
33
  extend ActiveSupport::Concern
7
34
 
8
35
  # This module creates compiled delegation methods dynamically at runtime, which makes
@@ -10,7 +37,14 @@ module ActiveRecord
10
37
  # may vary depending on the klass of a relation, so we create a subclass of Relation
11
38
  # for each different klass, and the delegations are compiled into that subclass only.
12
39
 
13
- delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to => :to_a
40
+ BLACKLISTED_ARRAY_METHODS = [
41
+ :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
42
+ :shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
43
+ :keep_if, :pop, :shift, :delete_at, :compact
44
+ ].to_set # :nodoc:
45
+
46
+ delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, to: :to_a
47
+
14
48
  delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
15
49
  :connection, :columns_hash, :to => :klass
16
50
 
@@ -38,7 +72,7 @@ module ActiveRecord
38
72
  RUBY
39
73
  else
40
74
  define_method method do |*args, &block|
41
- scoping { @klass.send(method, *args, &block) }
75
+ scoping { @klass.public_send(method, *args, &block) }
42
76
  end
43
77
  end
44
78
  end
@@ -57,13 +91,10 @@ module ActiveRecord
57
91
  def method_missing(method, *args, &block)
58
92
  if @klass.respond_to?(method)
59
93
  self.class.delegate_to_scoped_klass(method)
60
- scoping { @klass.send(method, *args, &block) }
61
- elsif Array.method_defined?(method)
62
- self.class.delegate method, :to => :to_a
63
- to_a.send(method, *args, &block)
94
+ scoping { @klass.public_send(method, *args, &block) }
64
95
  elsif arel.respond_to?(method)
65
96
  self.class.delegate method, :to => :arel
66
- arel.send(method, *args, &block)
97
+ arel.public_send(method, *args, &block)
67
98
  else
68
99
  super
69
100
  end
@@ -71,52 +102,36 @@ module ActiveRecord
71
102
  end
72
103
 
73
104
  module ClassMethods # :nodoc:
74
- @@subclasses = ThreadSafe::Cache.new(:initial_capacity => 2)
75
-
76
- def new(klass, *args)
77
- relation = relation_class_for(klass).allocate
78
- relation.__send__(:initialize, klass, *args)
79
- relation
80
- end
81
-
82
- # This doesn't have to be thread-safe. relation_class_for guarantees that this will only be
83
- # called exactly once for a given const name.
84
- def const_missing(name)
85
- const_set(name, Class.new(self) { include ClassSpecificRelation })
105
+ def create(klass, *args)
106
+ relation_class_for(klass).new(klass, *args)
86
107
  end
87
108
 
88
109
  private
89
- # Cache the constants in @@subclasses because looking them up via const_get
90
- # make instantiation significantly slower.
110
+
91
111
  def relation_class_for(klass)
92
- if klass && (klass_name = klass.name)
93
- my_cache = @@subclasses.compute_if_absent(self) { ThreadSafe::Cache.new }
94
- # This hash is keyed by klass.name to avoid memory leaks in development mode
95
- my_cache.compute_if_absent(klass_name) do
96
- # Cache#compute_if_absent guarantees that the block will only executed once for the given klass_name
97
- const_get("#{name.gsub('::', '_')}_#{klass_name.gsub('::', '_')}", false)
98
- end
99
- else
100
- ActiveRecord::Relation
101
- end
112
+ klass.relation_delegate_class(self)
102
113
  end
103
114
  end
104
115
 
105
116
  def respond_to?(method, include_private = false)
106
- super || Array.method_defined?(method) ||
107
- @klass.respond_to?(method, include_private) ||
117
+ super || @klass.respond_to?(method, include_private) ||
118
+ array_delegable?(method) ||
108
119
  arel.respond_to?(method, include_private)
109
120
  end
110
121
 
111
122
  protected
112
123
 
124
+ def array_delegable?(method)
125
+ Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
126
+ end
127
+
113
128
  def method_missing(method, *args, &block)
114
129
  if @klass.respond_to?(method)
115
- scoping { @klass.send(method, *args, &block) }
116
- elsif Array.method_defined?(method)
117
- to_a.send(method, *args, &block)
130
+ scoping { @klass.public_send(method, *args, &block) }
131
+ elsif array_delegable?(method)
132
+ to_a.public_send(method, *args, &block)
118
133
  elsif arel.respond_to?(method)
119
- arel.send(method, *args, &block)
134
+ arel.public_send(method, *args, &block)
120
135
  else
121
136
  super
122
137
  end
@@ -1,5 +1,7 @@
1
1
  module ActiveRecord
2
2
  module FinderMethods
3
+ ONE_AS_ONE = '1 AS one'
4
+
3
5
  # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
4
6
  # If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
5
7
  # is an integer, find by id coerces its arguments using +to_i+.
@@ -12,9 +14,11 @@ module ActiveRecord
12
14
  # Person.find([1]) # returns an array for the object with ID = 1
13
15
  # Person.where("administrator = 1").order("created_on DESC").find(1)
14
16
  #
15
- # Note that returned records may not be in the same order as the ids you
16
- # provide since database rows are unordered. Give an explicit <tt>order</tt>
17
- # to ensure the results are sorted.
17
+ # <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
18
+ #
19
+ # NOTE: The returned records may not be in the same order as the ids you
20
+ # provide since database rows are unordered. You'd need to provide an explicit <tt>order</tt>
21
+ # option if you want the results are sorted.
18
22
  #
19
23
  # ==== Find with lock
20
24
  #
@@ -29,9 +33,37 @@ module ActiveRecord
29
33
  # person.visits += 1
30
34
  # person.save!
31
35
  # end
36
+ #
37
+ # ==== Variations of +find+
38
+ #
39
+ # Person.where(name: 'Spartacus', rating: 4)
40
+ # # returns a chainable list (which can be empty).
41
+ #
42
+ # Person.find_by(name: 'Spartacus', rating: 4)
43
+ # # returns the first item or nil.
44
+ #
45
+ # Person.where(name: 'Spartacus', rating: 4).first_or_initialize
46
+ # # returns the first item or returns a new instance (requires you call .save to persist against the database).
47
+ #
48
+ # Person.where(name: 'Spartacus', rating: 4).first_or_create
49
+ # # returns the first item or creates it and returns it, available since Rails 3.2.1.
50
+ #
51
+ # ==== Alternatives for +find+
52
+ #
53
+ # Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
54
+ # # returns a boolean indicating if any record with the given conditions exist.
55
+ #
56
+ # Person.where(name: 'Spartacus', rating: 4).select("field1, field2, field3")
57
+ # # returns a chainable list of instances with only the mentioned fields.
58
+ #
59
+ # Person.where(name: 'Spartacus', rating: 4).ids
60
+ # # returns an Array of ids, available since Rails 3.2.1.
61
+ #
62
+ # Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
63
+ # # returns an Array of the required fields, available since Rails 3.1.
32
64
  def find(*args)
33
65
  if block_given?
34
- to_a.find(*args) { |*block_args| yield(*block_args) }
66
+ to_a.find { |*block_args| yield(*block_args) }
35
67
  else
36
68
  find_with_ids(*args)
37
69
  end
@@ -80,13 +112,22 @@ module ActiveRecord
80
112
  # Person.where(["user_name = :u", { u: user_name }]).first
81
113
  # Person.order("created_on DESC").offset(5).first
82
114
  # Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
115
+ #
116
+ # ==== Rails 3
117
+ #
118
+ # Person.first # SELECT "people".* FROM "people" LIMIT 1
119
+ #
120
+ # NOTE: Rails 3 may not order this query by the primary key and the order
121
+ # will depend on the database implementation. In order to ensure that behavior,
122
+ # use <tt>User.order(:id).first</tt> instead.
123
+ #
124
+ # ==== Rails 4
125
+ #
126
+ # Person.first # SELECT "people".* FROM "people" ORDER BY "people"."id" ASC LIMIT 1
127
+ #
83
128
  def first(limit = nil)
84
129
  if limit
85
- if order_values.empty? && primary_key
86
- order(arel_table[primary_key].asc).limit(limit).to_a
87
- else
88
- limit(limit).to_a
89
- end
130
+ find_first_with_limit(limit)
90
131
  else
91
132
  find_first
92
133
  end
@@ -161,9 +202,10 @@ module ActiveRecord
161
202
  conditions = conditions.id if Base === conditions
162
203
  return false if !conditions
163
204
 
164
- join_dependency = construct_join_dependency_for_association_find
165
- relation = construct_relation_for_association_find(join_dependency)
166
- relation = relation.except(:select, :order).select("1 AS one").limit(1)
205
+ relation = apply_join_dependency(self, construct_join_dependency)
206
+ return false if ActiveRecord::NullRelation === relation
207
+
208
+ relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)
167
209
 
168
210
  case conditions
169
211
  when Array, Hash
@@ -173,8 +215,6 @@ module ActiveRecord
173
215
  end
174
216
 
175
217
  connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
176
- rescue ThrowResult
177
- false
178
218
  end
179
219
 
180
220
  # This method is called whenever no records are found with either a single
@@ -199,64 +239,70 @@ module ActiveRecord
199
239
  raise RecordNotFound, error
200
240
  end
201
241
 
202
- protected
242
+ private
203
243
 
204
244
  def find_with_associations
205
- join_dependency = construct_join_dependency_for_association_find
206
- relation = construct_relation_for_association_find(join_dependency)
207
- rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
208
- join_dependency.instantiate(rows)
209
- rescue ThrowResult
210
- []
211
- end
245
+ join_dependency = construct_join_dependency
212
246
 
213
- def construct_join_dependency_for_association_find
214
- including = (eager_load_values + includes_values).uniq
215
- ActiveRecord::Associations::JoinDependency.new(@klass, including, joins_values)
247
+ aliases = join_dependency.aliases
248
+ relation = select aliases.columns
249
+ relation = apply_join_dependency(relation, join_dependency)
250
+
251
+ if block_given?
252
+ yield relation
253
+ else
254
+ if ActiveRecord::NullRelation === relation
255
+ []
256
+ else
257
+ rows = connection.select_all(relation.arel, 'SQL', relation.bind_values.dup)
258
+ join_dependency.instantiate(rows, aliases)
259
+ end
260
+ end
216
261
  end
217
262
 
218
- def construct_relation_for_association_calculations
219
- including = (eager_load_values + includes_values).uniq
220
- join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
221
- relation = except(:includes, :eager_load, :preload)
222
- apply_join_dependency(relation, join_dependency)
263
+ def construct_join_dependency(joins = [])
264
+ including = eager_load_values + includes_values
265
+ ActiveRecord::Associations::JoinDependency.new(@klass, including, joins)
223
266
  end
224
267
 
225
- def construct_relation_for_association_find(join_dependency)
226
- relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns + select_values)
227
- apply_join_dependency(relation, join_dependency)
268
+ def construct_relation_for_association_calculations
269
+ apply_join_dependency(self, construct_join_dependency(arel.froms.first))
228
270
  end
229
271
 
230
272
  def apply_join_dependency(relation, join_dependency)
231
- join_dependency.join_associations.each do |association|
232
- relation = association.join_relation(relation)
233
- end
234
-
235
- limitable_reflections = using_limitable_reflections?(join_dependency.reflections)
273
+ relation = relation.except(:includes, :eager_load, :preload)
274
+ relation = relation.joins join_dependency
236
275
 
237
- if !limitable_reflections && relation.limit_value
238
- limited_id_condition = construct_limited_ids_condition(relation.except(:select))
239
- relation = relation.where(limited_id_condition)
276
+ if using_limitable_reflections?(join_dependency.reflections)
277
+ relation
278
+ else
279
+ if relation.limit_value
280
+ limited_ids = limited_ids_for(relation)
281
+ limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
282
+ end
283
+ relation.except(:limit, :offset)
240
284
  end
241
-
242
- relation = relation.except(:limit, :offset) unless limitable_reflections
243
-
244
- relation
245
285
  end
246
286
 
247
- def construct_limited_ids_condition(relation)
248
- orders = relation.order_values.map { |val| val.presence }.compact
249
- values = @klass.connection.columns_for_distinct("#{quoted_table_name}.#{quoted_primary_key}", orders)
287
+ def limited_ids_for(relation)
288
+ values = @klass.connection.columns_for_distinct(
289
+ "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
250
290
 
251
- relation = relation.dup.select(values).distinct!
291
+ relation = relation.except(:select).select(values).distinct!
252
292
 
253
293
  id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
254
- ids_array = id_rows.map {|row| row[primary_key]}
294
+ id_rows.map {|row| row[primary_key]}
295
+ end
255
296
 
256
- ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
297
+ def using_limitable_reflections?(reflections)
298
+ reflections.none? { |r| r.collection? }
257
299
  end
258
300
 
301
+ protected
302
+
259
303
  def find_with_ids(*ids)
304
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
305
+
260
306
  expects_array = ids.first.kind_of?(Array)
261
307
  return ids.first if expects_array && ids.first.empty?
262
308
 
@@ -321,12 +367,15 @@ module ActiveRecord
321
367
  if loaded?
322
368
  @records.first
323
369
  else
324
- @first ||=
325
- if with_default_scope.order_values.empty? && primary_key
326
- order(arel_table[primary_key].asc).limit(1).to_a.first
327
- else
328
- limit(1).to_a.first
329
- end
370
+ @first ||= find_first_with_limit(1).first
371
+ end
372
+ end
373
+
374
+ def find_first_with_limit(limit)
375
+ if order_values.empty? && primary_key
376
+ order(arel_table[primary_key].asc).limit(limit).to_a
377
+ else
378
+ limit(limit).to_a
330
379
  end
331
380
  end
332
381
 
@@ -335,16 +384,12 @@ module ActiveRecord
335
384
  @records.last
336
385
  else
337
386
  @last ||=
338
- if offset_value || limit_value
387
+ if limit_value
339
388
  to_a.last
340
389
  else
341
390
  reverse_order.limit(1).to_a.first
342
391
  end
343
392
  end
344
393
  end
345
-
346
- def using_limitable_reflections?(reflections)
347
- reflections.none? { |r| r.collection? }
348
- end
349
394
  end
350
395
  end
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  # build a relation to merge in rather than directly merging
23
23
  # the values.
24
24
  def other
25
- other = Relation.new(relation.klass, relation.table)
25
+ other = Relation.create(relation.klass, relation.table)
26
26
  hash.each { |k, v|
27
27
  if k == :joins
28
28
  if Hash === v
@@ -30,8 +30,6 @@ module ActiveRecord
30
30
  else
31
31
  other.joins!(*v)
32
32
  end
33
- elsif k == :select
34
- other._select!(v)
35
33
  else
36
34
  other.send("#{k}!", v)
37
35
  end
@@ -44,10 +42,6 @@ module ActiveRecord
44
42
  attr_reader :relation, :values, :other
45
43
 
46
44
  def initialize(relation, other)
47
- if other.default_scoped? && other.klass != relation.klass
48
- other = other.with_default_scope
49
- end
50
-
51
45
  @relation = relation
52
46
  @values = other.values
53
47
  @other = other
@@ -68,13 +62,7 @@ module ActiveRecord
68
62
  # expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
69
63
  # `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
70
64
  # don't fall through the cracks.
71
- unless value.nil? || (value.blank? && false != value)
72
- if name == :select
73
- relation._select!(*value)
74
- else
75
- relation.send("#{name}!", *value)
76
- end
77
- end
65
+ relation.send("#{name}!", *value) unless value.nil? || (value.blank? && false != value)
78
66
  end
79
67
 
80
68
  merge_multi_values
@@ -106,9 +94,7 @@ module ActiveRecord
106
94
  [])
107
95
  relation.joins! rest
108
96
 
109
- join_dependency.join_associations.each do |association|
110
- @relation = association.join_relation(relation)
111
- end
97
+ @relation = relation.joins join_dependency
112
98
  end
113
99
  end
114
100
 
@@ -143,7 +129,7 @@ module ActiveRecord
143
129
  # override any order specified in the original relation
144
130
  relation.reorder! values[:order]
145
131
  elsif values[:order]
146
- # merge in order_values from r
132
+ # merge in order_values from relation
147
133
  relation.order! values[:order]
148
134
  end
149
135
 
@@ -161,7 +147,9 @@ module ActiveRecord
161
147
  end
162
148
 
163
149
  def filter_binds(lhs_binds, removed_wheres)
164
- set = Set.new removed_wheres.map { |x| x.left.name.to_s }
150
+ return lhs_binds if removed_wheres.empty?
151
+
152
+ set = Set.new removed_wheres.map { |x| x.left.name }
165
153
  lhs_binds.dup.delete_if { |col,_| set.include? col.name }
166
154
  end
167
155
 
@@ -182,7 +170,6 @@ module ActiveRecord
182
170
  w.respond_to?(:operator) && w.operator == :== && seen.include?(w.left)
183
171
  end
184
172
  end
185
-
186
173
  end
187
174
  end
188
175
  end