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.

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +368 -1
  3. data/lib/active_record/aggregations.rb +4 -3
  4. data/lib/active_record/association_relation.rb +13 -0
  5. data/lib/active_record/associations/association.rb +15 -3
  6. data/lib/active_record/associations/association_scope.rb +1 -0
  7. data/lib/active_record/associations/belongs_to_association.rb +5 -1
  8. data/lib/active_record/associations/builder/association.rb +1 -1
  9. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
  10. data/lib/active_record/associations/collection_association.rb +1 -7
  11. data/lib/active_record/associations/collection_proxy.rb +8 -7
  12. data/lib/active_record/associations/has_many_association.rb +8 -1
  13. data/lib/active_record/associations/has_many_through_association.rb +9 -0
  14. data/lib/active_record/associations/join_dependency.rb +8 -2
  15. data/lib/active_record/associations/preloader/association.rb +5 -1
  16. data/lib/active_record/associations/preloader.rb +4 -4
  17. data/lib/active_record/associations/singular_association.rb +2 -8
  18. data/lib/active_record/associations/through_association.rb +0 -6
  19. data/lib/active_record/associations.rb +1 -1
  20. data/lib/active_record/attribute_assignment.rb +1 -1
  21. data/lib/active_record/attribute_methods/dirty.rb +7 -1
  22. data/lib/active_record/attribute_methods.rb +3 -7
  23. data/lib/active_record/attribute_set/builder.rb +21 -11
  24. data/lib/active_record/attribute_set.rb +4 -0
  25. data/lib/active_record/autosave_association.rb +1 -1
  26. data/lib/active_record/base.rb +4 -5
  27. data/lib/active_record/callbacks.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -0
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -2
  30. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -24
  31. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +49 -17
  32. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +12 -1
  34. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +38 -5
  35. data/lib/active_record/connection_adapters/column.rb +1 -1
  36. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -3
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -2
  38. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  39. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  40. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  41. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -6
  42. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -9
  43. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -12
  44. data/lib/active_record/core.rb +15 -8
  45. data/lib/active_record/enum.rb +2 -3
  46. data/lib/active_record/errors.rb +6 -5
  47. data/lib/active_record/explain_subscriber.rb +1 -1
  48. data/lib/active_record/fixtures.rb +8 -6
  49. data/lib/active_record/gem_version.rb +2 -2
  50. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  51. data/lib/active_record/migration.rb +7 -4
  52. data/lib/active_record/model_schema.rb +1 -1
  53. data/lib/active_record/nested_attributes.rb +12 -2
  54. data/lib/active_record/persistence.rb +5 -3
  55. data/lib/active_record/railtie.rb +1 -1
  56. data/lib/active_record/railties/databases.rake +10 -7
  57. data/lib/active_record/reflection.rb +39 -27
  58. data/lib/active_record/relation/calculations.rb +8 -1
  59. data/lib/active_record/relation/delegation.rb +1 -1
  60. data/lib/active_record/relation/finder_methods.rb +3 -15
  61. data/lib/active_record/relation/merger.rb +24 -1
  62. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -1
  63. data/lib/active_record/relation/predicate_builder.rb +11 -2
  64. data/lib/active_record/relation/query_methods.rb +15 -18
  65. data/lib/active_record/relation/spawn_methods.rb +7 -3
  66. data/lib/active_record/relation.rb +2 -1
  67. data/lib/active_record/scoping/default.rb +1 -0
  68. data/lib/active_record/tasks/database_tasks.rb +3 -2
  69. data/lib/active_record/tasks/mysql_database_tasks.rb +30 -16
  70. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -8
  71. data/lib/active_record/transactions.rb +16 -4
  72. data/lib/active_record/type/boolean.rb +1 -0
  73. data/lib/active_record/type/date.rb +4 -0
  74. data/lib/active_record/type/decimal.rb +12 -2
  75. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  76. data/lib/active_record/type/serialized.rb +7 -1
  77. data/lib/active_record/validations/uniqueness.rb +15 -5
  78. data/lib/active_record.rb +2 -0
  79. 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(nil, self))
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(ActiveRecord::RecordNotDestroyed, self)
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 if ActiveRecord::Base.dump_schema_after_migration
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
- case ActiveRecord::Base.schema_format
50
- when :ruby then db_namespace["schema:dump"].invoke
51
- when :sql then db_namespace["structure:dump"].invoke
52
- else
53
- raise "unknown schema format #{ActiveRecord::Base.schema_format}"
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
- ref = {}
71
- _reflections.each do |name, reflection|
72
- parent_name, parent_reflection = reflection.parent_reflection
73
- if parent_name
74
- ref[parent_name] = parent_reflection
75
- else
76
- ref[name] = reflection
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[:class]
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[:class]
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, :compact, :select!
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
 
@@ -14,7 +14,8 @@ module ActiveRecord
14
14
  it for 'IN' conditions.
15
15
  MSG
16
16
 
17
- values = values.flatten
17
+ flat_values = values.flatten
18
+ values = flat_values unless flat_values.include?(nil)
18
19
  end
19
20
 
20
21
  return attribute.in([]) if values.empty? && nils.empty?
@@ -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
- hash = hash.dup
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
- register_handler(BasicObject, ->(attribute, value) { attribute.eq(value) })
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! do |rel|
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
- case value
969
- when String, Integer, ActiveRecord::StatementCache::Substitute
970
- @klass.columns_hash.include? column.to_s
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
- if from_value
1068
- columns
1069
- else
1070
- columns.map do |field|
1071
- if (Symbol === field || String === field) && columns_hash.key?(field.to_s)
1072
- arel_table[field]
1073
- else
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 !other.is_a?(Relation) && other.respond_to?(:to_proc)
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
- klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
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
- affected = @klass.connection.delete(stmt, 'SQL', bind_values)
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(Migrator.migrations_paths, version) do |migration|
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 = ActiveSupport::Base.schema_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('mysqldump')
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
- unless Kernel.system(*args)
64
- $stderr.puts "Could not dump the database structure. "\
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('mysql')
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
- Kernel.system(*args)
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(command)
133
- args = [command]
134
- args.concat(['--user', configuration['username']]) if configuration['username']
135
- args << "--password=#{configuration['password']}" if configuration['password']
136
- args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
137
- configuration.slice('host', 'port', 'socket').each do |k, v|
138
- args.concat([ "--#{k}", v.to_s ]) if v
139
- end
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
- args
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
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
50
+ args += search_path.split(',').map do |part|
51
+ "--schema=#{part.strip}"
52
+ end
52
53
  end
53
-
54
- command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
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
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
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