activerecord 4.2.0 → 4.2.11
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +657 -1
- data/lib/active_record.rb +3 -0
- data/lib/active_record/aggregations.rb +6 -3
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +5 -4
- data/lib/active_record/associations/association.rb +15 -3
- data/lib/active_record/associations/association_scope.rb +1 -0
- data/lib/active_record/associations/belongs_to_association.rb +13 -5
- data/lib/active_record/associations/builder/association.rb +1 -1
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
- data/lib/active_record/associations/collection_association.rb +35 -15
- data/lib/active_record/associations/collection_proxy.rb +15 -9
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +30 -15
- data/lib/active_record/associations/has_many_through_association.rb +11 -2
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +8 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +7 -1
- data/lib/active_record/associations/preloader.rb +4 -4
- data/lib/active_record/associations/preloader/association.rb +5 -1
- data/lib/active_record/associations/singular_association.rb +2 -8
- data/lib/active_record/associations/through_association.rb +11 -6
- data/lib/active_record/attribute.rb +15 -1
- data/lib/active_record/attribute_assignment.rb +2 -2
- data/lib/active_record/attribute_methods.rb +4 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +5 -0
- data/lib/active_record/attribute_methods/dirty.rb +14 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +5 -1
- data/lib/active_record/attribute_methods/write.rb +1 -1
- data/lib/active_record/attribute_set.rb +4 -0
- data/lib/active_record/attribute_set/builder.rb +32 -12
- data/lib/active_record/attributes.rb +8 -0
- data/lib/active_record/autosave_association.rb +24 -9
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +12 -6
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -16
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +87 -24
- data/lib/active_record/connection_adapters/abstract/transaction.rb +2 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +25 -7
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +73 -10
- data/lib/active_record/connection_adapters/column.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +7 -21
- data/lib/active_record/connection_adapters/mysql_adapter.rb +10 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +21 -13
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +12 -28
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +28 -15
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/enum.rb +2 -3
- data/lib/active_record/errors.rb +6 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +9 -7
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +16 -14
- data/lib/active_record/migration.rb +38 -10
- data/lib/active_record/model_schema.rb +4 -2
- data/lib/active_record/nested_attributes.rb +13 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +7 -4
- data/lib/active_record/railtie.rb +5 -3
- data/lib/active_record/railties/databases.rake +17 -24
- data/lib/active_record/reflection.rb +40 -28
- data/lib/active_record/relation.rb +3 -2
- data/lib/active_record/relation/calculations.rb +10 -3
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +4 -16
- data/lib/active_record/relation/merger.rb +24 -1
- data/lib/active_record/relation/predicate_builder.rb +32 -3
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +29 -27
- data/lib/active_record/relation/spawn_methods.rb +7 -3
- data/lib/active_record/schema_dumper.rb +1 -1
- data/lib/active_record/schema_migration.rb +1 -4
- data/lib/active_record/scoping/default.rb +1 -0
- data/lib/active_record/tasks/database_tasks.rb +5 -2
- data/lib/active_record/tasks/mysql_database_tasks.rb +30 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -8
- data/lib/active_record/transactions.rb +21 -11
- data/lib/active_record/type/boolean.rb +1 -0
- data/lib/active_record/type/date.rb +4 -0
- data/lib/active_record/type/date_time.rb +14 -3
- data/lib/active_record/type/decimal.rb +27 -3
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/integer.rb +9 -5
- data/lib/active_record/type/numeric.rb +1 -1
- data/lib/active_record/type/serialized.rb +7 -1
- data/lib/active_record/type/string.rb +4 -0
- data/lib/active_record/type/value.rb +9 -0
- data/lib/active_record/validations/uniqueness.rb +16 -6
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -6
- metadata +9 -7
@@ -42,15 +42,18 @@ db_namespace = namespace :db do
|
|
42
42
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
|
43
43
|
task :migrate => [:environment, :load_config] do
|
44
44
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
45
|
-
db_namespace['_dump'].invoke
|
45
|
+
db_namespace['_dump'].invoke
|
46
46
|
end
|
47
47
|
|
48
|
+
# IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
|
48
49
|
task :_dump do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
if ActiveRecord::Base.dump_schema_after_migration
|
51
|
+
case ActiveRecord::Base.schema_format
|
52
|
+
when :ruby then db_namespace["schema:dump"].invoke
|
53
|
+
when :sql then db_namespace["structure:dump"].invoke
|
54
|
+
else
|
55
|
+
raise "unknown schema format #{ActiveRecord::Base.schema_format}"
|
56
|
+
end
|
54
57
|
end
|
55
58
|
# Allow this task to be called as many times as required. An example is the
|
56
59
|
# migrate:redo task, which calls other two internally that depend on this one.
|
@@ -60,6 +63,8 @@ db_namespace = namespace :db do
|
|
60
63
|
namespace :migrate do
|
61
64
|
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
62
65
|
task :redo => [:environment, :load_config] do
|
66
|
+
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
|
67
|
+
|
63
68
|
if ENV['VERSION']
|
64
69
|
db_namespace['migrate:down'].invoke
|
65
70
|
db_namespace['migrate:up'].invoke
|
@@ -74,16 +79,17 @@ db_namespace = namespace :db do
|
|
74
79
|
|
75
80
|
# desc 'Runs the "up" for a given migration VERSION.'
|
76
81
|
task :up => [:environment, :load_config] do
|
82
|
+
raise "VERSION is required" if ENV["VERSION"] && ENV["VERSION"].empty?
|
83
|
+
|
77
84
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
78
|
-
raise 'VERSION is required' unless version
|
79
85
|
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
|
80
86
|
db_namespace['_dump'].invoke
|
81
87
|
end
|
82
88
|
|
83
89
|
# desc 'Runs the "down" for a given migration VERSION.'
|
84
90
|
task :down => [:environment, :load_config] do
|
91
|
+
raise "VERSION is required - To go down one migration, use db:rollback" if ENV["VERSION"] && ENV["VERSION"].empty?
|
85
92
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
86
|
-
raise 'VERSION is required - To go down one migration, run db:rollback' unless version
|
87
93
|
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
|
88
94
|
db_namespace['_dump'].invoke
|
89
95
|
end
|
@@ -93,26 +99,13 @@ db_namespace = namespace :db do
|
|
93
99
|
unless ActiveRecord::SchemaMigration.table_exists?
|
94
100
|
abort 'Schema migrations table does not exist yet.'
|
95
101
|
end
|
96
|
-
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
97
|
-
|
98
|
-
file_list =
|
99
|
-
ActiveRecord::Migrator.migrations_paths.flat_map do |path|
|
100
|
-
# match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
|
101
|
-
Dir.foreach(path).grep(/^(\d{3,})_(.+)\.rb$/) do
|
102
|
-
version = ActiveRecord::SchemaMigration.normalize_migration_number($1)
|
103
|
-
status = db_list.delete(version) ? 'up' : 'down'
|
104
|
-
[status, version, $2.humanize]
|
105
|
-
end
|
106
|
-
end
|
107
102
|
|
108
|
-
db_list.map! do |version|
|
109
|
-
['up', version, '********** NO FILE **********']
|
110
|
-
end
|
111
103
|
# output
|
112
104
|
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
113
105
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
114
106
|
puts "-" * 50
|
115
|
-
|
107
|
+
paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
108
|
+
ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
|
116
109
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
117
110
|
end
|
118
111
|
puts
|
@@ -286,7 +279,7 @@ db_namespace = namespace :db do
|
|
286
279
|
end
|
287
280
|
|
288
281
|
desc "Recreate the databases from the structure.sql file"
|
289
|
-
task :load => [:
|
282
|
+
task :load => [:load_config] do
|
290
283
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
|
291
284
|
end
|
292
285
|
|
@@ -7,8 +7,8 @@ module ActiveRecord
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
class_attribute :_reflections
|
11
|
-
class_attribute :aggregate_reflections
|
10
|
+
class_attribute :_reflections, instance_writer: false
|
11
|
+
class_attribute :aggregate_reflections, instance_writer: false
|
12
12
|
self._reflections = {}
|
13
13
|
self.aggregate_reflections = {}
|
14
14
|
end
|
@@ -32,6 +32,7 @@ module ActiveRecord
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.add_reflection(ar, name, reflection)
|
35
|
+
ar.clear_reflections_cache
|
35
36
|
ar._reflections = ar._reflections.merge(name.to_s => reflection)
|
36
37
|
end
|
37
38
|
|
@@ -67,16 +68,21 @@ module ActiveRecord
|
|
67
68
|
#
|
68
69
|
# @api public
|
69
70
|
def reflections
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
71
|
+
@__reflections ||= begin
|
72
|
+
ref = {}
|
73
|
+
|
74
|
+
_reflections.each do |name, reflection|
|
75
|
+
parent_name, parent_reflection = reflection.parent_reflection
|
76
|
+
|
77
|
+
if parent_name
|
78
|
+
ref[parent_name] = parent_reflection
|
79
|
+
else
|
80
|
+
ref[name] = reflection
|
81
|
+
end
|
77
82
|
end
|
83
|
+
|
84
|
+
ref
|
78
85
|
end
|
79
|
-
ref
|
80
86
|
end
|
81
87
|
|
82
88
|
# Returns an array of AssociationReflection objects for all the
|
@@ -116,6 +122,10 @@ module ActiveRecord
|
|
116
122
|
def reflect_on_all_autosave_associations
|
117
123
|
reflections.values.select { |reflection| reflection.options[:autosave] }
|
118
124
|
end
|
125
|
+
|
126
|
+
def clear_reflections_cache #:nodoc:
|
127
|
+
@__reflections = nil
|
128
|
+
end
|
119
129
|
end
|
120
130
|
|
121
131
|
# Holds all the methods that are shared between MacroReflection, AssociationReflection
|
@@ -161,6 +171,20 @@ module ActiveRecord
|
|
161
171
|
|
162
172
|
macro
|
163
173
|
end
|
174
|
+
|
175
|
+
def inverse_of
|
176
|
+
return unless inverse_name
|
177
|
+
|
178
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
179
|
+
end
|
180
|
+
|
181
|
+
def check_validity_of_inverse!
|
182
|
+
unless polymorphic?
|
183
|
+
if has_inverse? && inverse_of.nil?
|
184
|
+
raise InverseOfAssociationNotFoundError.new(self)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
164
188
|
end
|
165
189
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
166
190
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
@@ -196,7 +220,7 @@ module ActiveRecord
|
|
196
220
|
@scope = scope
|
197
221
|
@options = options
|
198
222
|
@active_record = active_record
|
199
|
-
@klass = options[:
|
223
|
+
@klass = options[:anonymous_class]
|
200
224
|
@plural_name = active_record.pluralize_table_names ?
|
201
225
|
name.to_s.pluralize : name.to_s
|
202
226
|
end
|
@@ -303,7 +327,7 @@ module ActiveRecord
|
|
303
327
|
end
|
304
328
|
|
305
329
|
def foreign_key
|
306
|
-
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
330
|
+
@foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
|
307
331
|
end
|
308
332
|
|
309
333
|
def association_foreign_key
|
@@ -331,14 +355,6 @@ module ActiveRecord
|
|
331
355
|
check_validity_of_inverse!
|
332
356
|
end
|
333
357
|
|
334
|
-
def check_validity_of_inverse!
|
335
|
-
unless polymorphic?
|
336
|
-
if has_inverse? && inverse_of.nil?
|
337
|
-
raise InverseOfAssociationNotFoundError.new(self)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
358
|
def check_preloadable!
|
343
359
|
return unless scope
|
344
360
|
|
@@ -387,12 +403,6 @@ module ActiveRecord
|
|
387
403
|
inverse_name
|
388
404
|
end
|
389
405
|
|
390
|
-
def inverse_of
|
391
|
-
return unless inverse_name
|
392
|
-
|
393
|
-
@inverse_of ||= klass._reflect_on_association inverse_name
|
394
|
-
end
|
395
|
-
|
396
406
|
def polymorphic_inverse_of(associated_class)
|
397
407
|
if has_inverse?
|
398
408
|
if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of])
|
@@ -499,7 +509,7 @@ module ActiveRecord
|
|
499
509
|
# returns either nil or the inverse association name that it finds.
|
500
510
|
def automatic_inverse_of
|
501
511
|
if can_find_inverse_of_automatically?(self)
|
502
|
-
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
|
512
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
|
503
513
|
|
504
514
|
begin
|
505
515
|
reflection = klass._reflect_on_association(inverse_name)
|
@@ -632,7 +642,7 @@ module ActiveRecord
|
|
632
642
|
|
633
643
|
def initialize(delegate_reflection)
|
634
644
|
@delegate_reflection = delegate_reflection
|
635
|
-
@klass = delegate_reflection.options[:
|
645
|
+
@klass = delegate_reflection.options[:anonymous_class]
|
636
646
|
@source_reflection_name = delegate_reflection.options[:source]
|
637
647
|
end
|
638
648
|
|
@@ -865,6 +875,8 @@ module ActiveRecord
|
|
865
875
|
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
866
876
|
end
|
867
877
|
|
878
|
+
def inverse_name; delegate_reflection.send(:inverse_name); end
|
879
|
+
|
868
880
|
private
|
869
881
|
def derive_class_name
|
870
882
|
# get the class_name of the belongs_to association of the through reflection
|
@@ -474,7 +474,8 @@ module ActiveRecord
|
|
474
474
|
stmt.wheres = arel.constraints
|
475
475
|
end
|
476
476
|
|
477
|
-
|
477
|
+
bvs = arel.bind_values + bind_values
|
478
|
+
affected = @klass.connection.delete(stmt, 'SQL', bvs)
|
478
479
|
|
479
480
|
reset
|
480
481
|
affected
|
@@ -568,7 +569,7 @@ module ActiveRecord
|
|
568
569
|
[name, binds.fetch(name.to_s) {
|
569
570
|
case where.right
|
570
571
|
when Array then where.right.map(&:val)
|
571
|
-
|
572
|
+
when Arel::Nodes::Casted
|
572
573
|
where.right.val
|
573
574
|
end
|
574
575
|
}]
|
@@ -36,9 +36,15 @@ module ActiveRecord
|
|
36
36
|
# Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
|
37
37
|
# between databases. In invalid cases, an error from the database is thrown.
|
38
38
|
def count(column_name = nil, options = {})
|
39
|
+
if options.present? && !ActiveRecord.const_defined?(:DeprecatedFinders)
|
40
|
+
raise ArgumentError, "Relation#count does not support finder options anymore. " \
|
41
|
+
"Please build a scope and then call count on it or use the " \
|
42
|
+
"activerecord-deprecated_finders gem to enable this functionality."
|
43
|
+
|
44
|
+
end
|
45
|
+
|
39
46
|
# TODO: Remove options argument as soon we remove support to
|
40
47
|
# activerecord-deprecated_finders.
|
41
|
-
column_name, options = nil, column_name if column_name.is_a?(Hash)
|
42
48
|
calculate(:count, column_name, options)
|
43
49
|
end
|
44
50
|
|
@@ -88,7 +94,7 @@ module ActiveRecord
|
|
88
94
|
#
|
89
95
|
# There are two basic forms of output:
|
90
96
|
#
|
91
|
-
# * Single aggregate value: The single value is type cast to
|
97
|
+
# * Single aggregate value: The single value is type cast to Integer for COUNT, Float
|
92
98
|
# for AVG, and the given column's type for everything else.
|
93
99
|
#
|
94
100
|
# * Grouped values: This returns an ordered hash of the values and groups them. It
|
@@ -281,6 +287,7 @@ module ActiveRecord
|
|
281
287
|
else
|
282
288
|
group_fields = group_attrs
|
283
289
|
end
|
290
|
+
group_fields = arel_columns(group_fields)
|
284
291
|
|
285
292
|
group_aliases = group_fields.map { |field|
|
286
293
|
column_alias_for(field)
|
@@ -303,7 +310,7 @@ module ActiveRecord
|
|
303
310
|
operation,
|
304
311
|
distinct).as(aggregate_alias)
|
305
312
|
]
|
306
|
-
select_values += select_values unless having_values.empty?
|
313
|
+
select_values += self.select_values unless having_values.empty?
|
307
314
|
|
308
315
|
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
|
309
316
|
if field.respond_to?(:as)
|
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
BLACKLISTED_ARRAY_METHODS = [
|
41
41
|
:compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
|
42
42
|
:shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
|
43
|
-
:keep_if, :pop, :shift, :delete_at, :
|
43
|
+
:keep_if, :pop, :shift, :delete_at, :select!
|
44
44
|
].to_set # :nodoc:
|
45
45
|
|
46
46
|
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
|
@@ -114,23 +114,11 @@ module ActiveRecord
|
|
114
114
|
# Find the first record (or first N records if a parameter is supplied).
|
115
115
|
# If no order is defined it will order by primary key.
|
116
116
|
#
|
117
|
-
# Person.first # returns the first object fetched by SELECT * FROM people
|
117
|
+
# Person.first # returns the first object fetched by SELECT * FROM people ORDER BY people.id LIMIT 1
|
118
118
|
# Person.where(["user_name = ?", user_name]).first
|
119
119
|
# Person.where(["user_name = :u", { u: user_name }]).first
|
120
120
|
# Person.order("created_on DESC").offset(5).first
|
121
|
-
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
|
122
|
-
#
|
123
|
-
# ==== Rails 3
|
124
|
-
#
|
125
|
-
# Person.first # SELECT "people".* FROM "people" LIMIT 1
|
126
|
-
#
|
127
|
-
# NOTE: Rails 3 may not order this query by the primary key and the order
|
128
|
-
# will depend on the database implementation. In order to ensure that behavior,
|
129
|
-
# use <tt>User.order(:id).first</tt> instead.
|
130
|
-
#
|
131
|
-
# ==== Rails 4
|
132
|
-
#
|
133
|
-
# Person.first # SELECT "people".* FROM "people" ORDER BY "people"."id" ASC LIMIT 1
|
121
|
+
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
134
122
|
#
|
135
123
|
def first(limit = nil)
|
136
124
|
if limit
|
@@ -307,7 +295,7 @@ module ActiveRecord
|
|
307
295
|
relation = relation.where(conditions)
|
308
296
|
else
|
309
297
|
unless conditions == :none
|
310
|
-
relation = where(primary_key => conditions)
|
298
|
+
relation = relation.where(primary_key => conditions)
|
311
299
|
end
|
312
300
|
end
|
313
301
|
|
@@ -379,7 +367,7 @@ module ActiveRecord
|
|
379
367
|
def construct_relation_for_association_calculations
|
380
368
|
from = arel.froms.first
|
381
369
|
if Arel::Table === from
|
382
|
-
apply_join_dependency(self, construct_join_dependency)
|
370
|
+
apply_join_dependency(self, construct_join_dependency(joins_values))
|
383
371
|
else
|
384
372
|
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
|
385
373
|
# There are no tests that test this branch, but presumably it's
|
@@ -51,7 +51,8 @@ module ActiveRecord
|
|
51
51
|
|
52
52
|
NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
|
53
53
|
Relation::MULTI_VALUE_METHODS -
|
54
|
-
[:joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
|
54
|
+
[:includes, :preload, :joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
|
55
|
+
|
55
56
|
|
56
57
|
def normal_values
|
57
58
|
NORMAL_VALUES
|
@@ -75,6 +76,7 @@ module ActiveRecord
|
|
75
76
|
|
76
77
|
merge_multi_values
|
77
78
|
merge_single_values
|
79
|
+
merge_preloads
|
78
80
|
merge_joins
|
79
81
|
|
80
82
|
relation
|
@@ -82,6 +84,27 @@ module ActiveRecord
|
|
82
84
|
|
83
85
|
private
|
84
86
|
|
87
|
+
def merge_preloads
|
88
|
+
return if other.preload_values.empty? && other.includes_values.empty?
|
89
|
+
|
90
|
+
if other.klass == relation.klass
|
91
|
+
relation.preload!(*other.preload_values) unless other.preload_values.empty?
|
92
|
+
relation.includes!(other.includes_values) unless other.includes_values.empty?
|
93
|
+
else
|
94
|
+
reflection = relation.klass.reflect_on_all_associations.find do |r|
|
95
|
+
r.class_name == other.klass.name
|
96
|
+
end || return
|
97
|
+
|
98
|
+
unless other.preload_values.empty?
|
99
|
+
relation.preload! reflection.name => other.preload_values
|
100
|
+
end
|
101
|
+
|
102
|
+
unless other.includes_values.empty?
|
103
|
+
relation.includes! reflection.name => other.includes_values
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
85
108
|
def merge_joins
|
86
109
|
return if other.joins_values.blank?
|
87
110
|
|
@@ -6,7 +6,9 @@ module ActiveRecord
|
|
6
6
|
autoload :ArrayHandler, 'active_record/relation/predicate_builder/array_handler'
|
7
7
|
|
8
8
|
def self.resolve_column_aliases(klass, hash)
|
9
|
-
|
9
|
+
# This method is a hot spot, so for now, use Hash[] to dup the hash.
|
10
|
+
# https://bugs.ruby-lang.org/issues/7166
|
11
|
+
hash = Hash[hash]
|
10
12
|
hash.keys.grep(Symbol) do |key|
|
11
13
|
if klass.attribute_alias? key
|
12
14
|
hash[klass.attribute_alias(key)] = hash.delete key
|
@@ -56,11 +58,18 @@ module ActiveRecord
|
|
56
58
|
# For polymorphic relationships, find the foreign key and type:
|
57
59
|
# PriceEstimate.where(estimate_of: treasure)
|
58
60
|
if klass && reflection = klass._reflect_on_association(column)
|
59
|
-
|
61
|
+
base_class = polymorphic_base_class_from_value(value)
|
62
|
+
|
63
|
+
if reflection.polymorphic? && base_class
|
60
64
|
queries << build(table[reflection.foreign_type], base_class)
|
61
65
|
end
|
62
66
|
|
63
67
|
column = reflection.foreign_key
|
68
|
+
|
69
|
+
if base_class
|
70
|
+
primary_key = reflection.association_primary_key(base_class)
|
71
|
+
value = convert_value_to_association_ids(value, primary_key)
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
queries << build(table[column], value)
|
@@ -105,7 +114,8 @@ module ActiveRecord
|
|
105
114
|
@handlers.unshift([klass, handler])
|
106
115
|
end
|
107
116
|
|
108
|
-
|
117
|
+
BASIC_OBJECT_HANDLER = ->(attribute, value) { attribute.eq(value) } # :nodoc:
|
118
|
+
register_handler(BasicObject, BASIC_OBJECT_HANDLER)
|
109
119
|
# FIXME: I think we need to deprecate this behavior
|
110
120
|
register_handler(Class, ->(attribute, value) { attribute.eq(value.name) })
|
111
121
|
register_handler(Base, ->(attribute, value) { attribute.eq(value.id) })
|
@@ -122,5 +132,24 @@ module ActiveRecord
|
|
122
132
|
@handlers.detect { |klass, _| klass === object }.last
|
123
133
|
end
|
124
134
|
private_class_method :handler_for
|
135
|
+
|
136
|
+
def self.convert_value_to_association_ids(value, primary_key)
|
137
|
+
case value
|
138
|
+
when Relation
|
139
|
+
value.select(primary_key)
|
140
|
+
when Array
|
141
|
+
value.map { |v| convert_value_to_association_ids(v, primary_key) }
|
142
|
+
when Base
|
143
|
+
value._read_attribute(primary_key)
|
144
|
+
else
|
145
|
+
value
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.can_be_bound?(value) # :nodoc:
|
150
|
+
!value.nil? &&
|
151
|
+
!value.is_a?(Hash) &&
|
152
|
+
handler_for(value) == BASIC_OBJECT_HANDLER
|
153
|
+
end
|
125
154
|
end
|
126
155
|
end
|