activerecord 4.2.1 → 4.2.7.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +368 -1
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +13 -0
- 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 +5 -1
- data/lib/active_record/associations/builder/association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
- data/lib/active_record/associations/collection_association.rb +1 -7
- data/lib/active_record/associations/collection_proxy.rb +8 -7
- data/lib/active_record/associations/has_many_association.rb +8 -1
- data/lib/active_record/associations/has_many_through_association.rb +9 -0
- data/lib/active_record/associations/join_dependency.rb +8 -2
- data/lib/active_record/associations/preloader/association.rb +5 -1
- data/lib/active_record/associations/preloader.rb +4 -4
- data/lib/active_record/associations/singular_association.rb +2 -8
- data/lib/active_record/associations/through_association.rb +0 -6
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +7 -1
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +21 -11
- data/lib/active_record/attribute_set.rb +4 -0
- data/lib/active_record/autosave_association.rb +1 -1
- 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 +4 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -24
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +49 -17
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +12 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +38 -5
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -12
- data/lib/active_record/core.rb +15 -8
- 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 +8 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/migration.rb +7 -4
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +12 -2
- data/lib/active_record/persistence.rb +5 -3
- data/lib/active_record/railtie.rb +1 -1
- data/lib/active_record/railties/databases.rake +10 -7
- data/lib/active_record/reflection.rb +39 -27
- data/lib/active_record/relation/calculations.rb +8 -1
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +3 -15
- data/lib/active_record/relation/merger.rb +24 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -2
- data/lib/active_record/relation/query_methods.rb +15 -18
- data/lib/active_record/relation/spawn_methods.rb +7 -3
- data/lib/active_record/relation.rb +2 -1
- data/lib/active_record/scoping/default.rb +1 -0
- data/lib/active_record/tasks/database_tasks.rb +3 -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 +16 -4
- data/lib/active_record/type/boolean.rb +1 -0
- data/lib/active_record/type/date.rb +4 -0
- data/lib/active_record/type/decimal.rb +12 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/serialized.rb +7 -1
- data/lib/active_record/validations/uniqueness.rb +15 -5
- data/lib/active_record.rb +2 -0
- metadata +9 -7
@@ -139,7 +139,7 @@ module ActiveRecord
|
|
139
139
|
# Attributes marked as readonly are silently ignored if the record is
|
140
140
|
# being updated.
|
141
141
|
def save!(*)
|
142
|
-
create_or_update || raise(RecordNotSaved.new(
|
142
|
+
create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
|
143
143
|
end
|
144
144
|
|
145
145
|
# Deletes the record in the database and freezes this instance to
|
@@ -168,6 +168,7 @@ module ActiveRecord
|
|
168
168
|
def destroy
|
169
169
|
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
170
170
|
destroy_associations
|
171
|
+
self.class.connection.add_transaction_record(self)
|
171
172
|
destroy_row if persisted?
|
172
173
|
@destroyed = true
|
173
174
|
freeze
|
@@ -181,7 +182,7 @@ module ActiveRecord
|
|
181
182
|
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
|
182
183
|
# ActiveRecord::Callbacks for further details.
|
183
184
|
def destroy!
|
184
|
-
destroy || raise(
|
185
|
+
destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
|
185
186
|
end
|
186
187
|
|
187
188
|
# Returns an instance of the specified +klass+ with the attributes of the
|
@@ -368,7 +369,7 @@ module ActiveRecord
|
|
368
369
|
# # => #<Account id: 1, email: 'account@example.com'>
|
369
370
|
#
|
370
371
|
# Attributes are reloaded from the database, and caches busted, in
|
371
|
-
# particular the associations cache.
|
372
|
+
# particular the associations cache and the QueryCache.
|
372
373
|
#
|
373
374
|
# If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
|
374
375
|
# is raised. Otherwise, in addition to the in-place modification the method
|
@@ -406,6 +407,7 @@ module ActiveRecord
|
|
406
407
|
def reload(options = nil)
|
407
408
|
clear_aggregation_cache
|
408
409
|
clear_association_cache
|
410
|
+
self.class.connection.clear_query_cache
|
409
411
|
|
410
412
|
fresh_object =
|
411
413
|
if options && options[:lock]
|
@@ -147,8 +147,8 @@ end_warning
|
|
147
147
|
ActiveSupport.on_load(:active_record) do
|
148
148
|
ActionDispatch::Reloader.send(hook) do
|
149
149
|
if ActiveRecord::Base.connected?
|
150
|
-
ActiveRecord::Base.clear_reloadable_connections!
|
151
150
|
ActiveRecord::Base.clear_cache!
|
151
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
@@ -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.
|
@@ -240,7 +243,7 @@ db_namespace = namespace :db do
|
|
240
243
|
end
|
241
244
|
|
242
245
|
desc 'Load a schema.rb file into the database'
|
243
|
-
task :load => [:load_config] do
|
246
|
+
task :load => [:environment, :load_config] do
|
244
247
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
|
245
248
|
end
|
246
249
|
|
@@ -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])
|
@@ -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
|
@@ -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
|
|
@@ -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)
|
@@ -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
|
@@ -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
|
@@ -112,7 +114,8 @@ module ActiveRecord
|
|
112
114
|
@handlers.unshift([klass, handler])
|
113
115
|
end
|
114
116
|
|
115
|
-
|
117
|
+
BASIC_OBJECT_HANDLER = ->(attribute, value) { attribute.eq(value) } # :nodoc:
|
118
|
+
register_handler(BasicObject, BASIC_OBJECT_HANDLER)
|
116
119
|
# FIXME: I think we need to deprecate this behavior
|
117
120
|
register_handler(Class, ->(attribute, value) { attribute.eq(value.name) })
|
118
121
|
register_handler(Base, ->(attribute, value) { attribute.eq(value.id) })
|
@@ -142,5 +145,11 @@ module ActiveRecord
|
|
142
145
|
value
|
143
146
|
end
|
144
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
|
145
154
|
end
|
146
155
|
end
|
@@ -258,7 +258,7 @@ module ActiveRecord
|
|
258
258
|
def _select!(*fields) # :nodoc:
|
259
259
|
fields.flatten!
|
260
260
|
fields.map! do |field|
|
261
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field) : field
|
261
|
+
klass.attribute_alias?(field) ? klass.attribute_alias(field).to_sym : field
|
262
262
|
end
|
263
263
|
self.select_values += fields
|
264
264
|
self
|
@@ -907,9 +907,9 @@ module ActiveRecord
|
|
907
907
|
def where_unscoping(target_value)
|
908
908
|
target_value = target_value.to_s
|
909
909
|
|
910
|
-
where_values.reject
|
910
|
+
self.where_values = where_values.reject do |rel|
|
911
911
|
case rel
|
912
|
-
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThanOrEqual
|
912
|
+
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
913
913
|
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
|
914
914
|
subrelation.name == target_value
|
915
915
|
end
|
@@ -965,12 +965,9 @@ module ActiveRecord
|
|
965
965
|
|
966
966
|
def create_binds(opts)
|
967
967
|
bindable, non_binds = opts.partition do |column, value|
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
else
|
972
|
-
false
|
973
|
-
end
|
968
|
+
PredicateBuilder.can_be_bound?(value) &&
|
969
|
+
@klass.columns_hash.include?(column.to_s) &&
|
970
|
+
!@klass.reflect_on_aggregation(column)
|
974
971
|
end
|
975
972
|
|
976
973
|
association_binds, non_binds = non_binds.partition do |column, value|
|
@@ -980,6 +977,8 @@ module ActiveRecord
|
|
980
977
|
new_opts = {}
|
981
978
|
binds = []
|
982
979
|
|
980
|
+
connection = self.connection
|
981
|
+
|
983
982
|
bindable.each do |(column,value)|
|
984
983
|
binds.push [@klass.columns_hash[column.to_s], value]
|
985
984
|
new_opts[column] = connection.substitute_at(column)
|
@@ -1064,15 +1063,13 @@ module ActiveRecord
|
|
1064
1063
|
end
|
1065
1064
|
|
1066
1065
|
def arel_columns(columns)
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
field
|
1075
|
-
end
|
1066
|
+
columns.map do |field|
|
1067
|
+
if (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_value
|
1068
|
+
arel_table[field]
|
1069
|
+
elsif Symbol === field
|
1070
|
+
connection.quote_table_name(field.to_s)
|
1071
|
+
else
|
1072
|
+
field
|
1076
1073
|
end
|
1077
1074
|
end
|
1078
1075
|
end
|
@@ -12,6 +12,7 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
|
14
14
|
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
|
15
|
+
#
|
15
16
|
# Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
|
16
17
|
# # Performs a single join query with both where conditions.
|
17
18
|
#
|
@@ -37,11 +38,14 @@ module ActiveRecord
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def merge!(other) # :nodoc:
|
40
|
-
if
|
41
|
+
if other.is_a?(Hash)
|
42
|
+
Relation::HashMerger.new(self, other).merge
|
43
|
+
elsif other.is_a?(Relation)
|
44
|
+
Relation::Merger.new(self, other).merge
|
45
|
+
elsif other.respond_to?(:to_proc)
|
41
46
|
instance_exec(&other)
|
42
47
|
else
|
43
|
-
|
44
|
-
klass.new(self, other).merge
|
48
|
+
raise ArgumentError, "#{other.inspect} is not an ActiveRecord::Relation"
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -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
|
@@ -95,6 +95,7 @@ module ActiveRecord
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def build_default_scope(base_rel = relation) # :nodoc:
|
98
|
+
return if abstract_class?
|
98
99
|
if !Base.is_a?(method(:default_scope).owner)
|
99
100
|
# The user has defined their own default scope method, so call that
|
100
101
|
evaluate_default_scope { default_scope }
|
@@ -134,9 +134,10 @@ module ActiveRecord
|
|
134
134
|
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
135
135
|
scope = ENV['SCOPE']
|
136
136
|
verbose_was, Migration.verbose = Migration.verbose, verbose
|
137
|
-
Migrator.migrate(
|
137
|
+
Migrator.migrate(migrations_paths, version) do |migration|
|
138
138
|
scope.blank? || scope == migration.scope
|
139
139
|
end
|
140
|
+
ActiveRecord::Base.clear_cache!
|
140
141
|
ensure
|
141
142
|
Migration.verbose = verbose_was
|
142
143
|
end
|
@@ -197,7 +198,7 @@ module ActiveRecord
|
|
197
198
|
load_schema_current(format, file)
|
198
199
|
end
|
199
200
|
|
200
|
-
def schema_file(format =
|
201
|
+
def schema_file(format = ActiveRecord::Base.schema_format)
|
201
202
|
case format
|
202
203
|
when :ruby
|
203
204
|
File.join(db_dir, "schema.rb")
|
@@ -56,21 +56,20 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def structure_dump(filename)
|
59
|
-
args = prepare_command_options
|
59
|
+
args = prepare_command_options
|
60
60
|
args.concat(["--result-file", "#{filename}"])
|
61
61
|
args.concat(["--no-data"])
|
62
62
|
args.concat(["#{configuration['database']}"])
|
63
|
-
|
64
|
-
|
65
|
-
"Make sure `mysqldump` is in your PATH and check the command output for warnings."
|
66
|
-
end
|
63
|
+
|
64
|
+
run_cmd('mysqldump', args, 'dumping')
|
67
65
|
end
|
68
66
|
|
69
67
|
def structure_load(filename)
|
70
|
-
args = prepare_command_options
|
68
|
+
args = prepare_command_options
|
71
69
|
args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
|
72
70
|
args.concat(["--database", "#{configuration['database']}"])
|
73
|
-
|
71
|
+
|
72
|
+
run_cmd('mysql', args, 'loading')
|
74
73
|
end
|
75
74
|
|
76
75
|
private
|
@@ -129,16 +128,31 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
|
|
129
128
|
$stdin.gets.strip
|
130
129
|
end
|
131
130
|
|
132
|
-
def prepare_command_options
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
def prepare_command_options
|
132
|
+
{
|
133
|
+
'host' => '--host',
|
134
|
+
'port' => '--port',
|
135
|
+
'socket' => '--socket',
|
136
|
+
'username' => '--user',
|
137
|
+
'password' => '--password',
|
138
|
+
'encoding' => '--default-character-set',
|
139
|
+
'sslca' => '--ssl-ca',
|
140
|
+
'sslcert' => '--ssl-cert',
|
141
|
+
'sslcapath' => '--ssl-capath',
|
142
|
+
'sslcipher' => '--ssl-cipher',
|
143
|
+
'sslkey' => '--ssl-key'
|
144
|
+
}.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
|
145
|
+
end
|
146
|
+
|
147
|
+
def run_cmd(cmd, args, action)
|
148
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
149
|
+
end
|
140
150
|
|
141
|
-
|
151
|
+
def run_cmd_error(cmd, args, action)
|
152
|
+
msg = "failed to execute:\n"
|
153
|
+
msg << "#{cmd}"
|
154
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
155
|
+
msg
|
142
156
|
end
|
143
157
|
end
|
144
158
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'shellwords'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module Tasks # :nodoc:
|
5
3
|
class PostgreSQLDatabaseTasks # :nodoc:
|
@@ -46,20 +44,22 @@ module ActiveRecord
|
|
46
44
|
|
47
45
|
def structure_dump(filename)
|
48
46
|
set_psql_env
|
47
|
+
args = ['-s', '-x', '-O', '-f', filename]
|
49
48
|
search_path = configuration['schema_search_path']
|
50
49
|
unless search_path.blank?
|
51
|
-
|
50
|
+
args += search_path.split(',').map do |part|
|
51
|
+
"--schema=#{part.strip}"
|
52
|
+
end
|
52
53
|
end
|
53
|
-
|
54
|
-
|
55
|
-
raise 'Error dumping database' unless Kernel.system(command)
|
56
|
-
|
54
|
+
args << configuration['database']
|
55
|
+
run_cmd('pg_dump', args, 'dumping')
|
57
56
|
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
58
57
|
end
|
59
58
|
|
60
59
|
def structure_load(filename)
|
61
60
|
set_psql_env
|
62
|
-
|
61
|
+
args = [ '-q', '-f', filename, configuration['database'] ]
|
62
|
+
run_cmd('psql', args, 'loading')
|
63
63
|
end
|
64
64
|
|
65
65
|
private
|
@@ -85,6 +85,17 @@ module ActiveRecord
|
|
85
85
|
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
|
86
86
|
ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
|
87
87
|
end
|
88
|
+
|
89
|
+
def run_cmd(cmd, args, action)
|
90
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def run_cmd_error(cmd, args, action)
|
94
|
+
msg = "failed to execute:\n"
|
95
|
+
msg << "#{cmd} #{args.join(' ')}\n\n"
|
96
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
97
|
+
msg
|
98
|
+
end
|
88
99
|
end
|
89
100
|
end
|
90
101
|
end
|