activerecord 5.2.1 → 5.2.2

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +107 -0
  3. data/lib/active_record/association_relation.rb +3 -3
  4. data/lib/active_record/associations/association.rb +8 -0
  5. data/lib/active_record/associations/collection_association.rb +5 -3
  6. data/lib/active_record/associations/has_many_association.rb +8 -0
  7. data/lib/active_record/associations/has_many_through_association.rb +22 -0
  8. data/lib/active_record/attribute_methods/dirty.rb +13 -8
  9. data/lib/active_record/autosave_association.rb +5 -5
  10. data/lib/active_record/callbacks.rb +1 -1
  11. data/lib/active_record/collection_cache_key.rb +2 -2
  12. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -1
  13. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  14. data/lib/active_record/connection_adapters/abstract/database_statements.rb +5 -0
  15. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  16. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +10 -1
  17. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +7 -1
  18. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +6 -2
  19. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  20. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
  21. data/lib/active_record/enum.rb +1 -0
  22. data/lib/active_record/errors.rb +1 -1
  23. data/lib/active_record/gem_version.rb +1 -1
  24. data/lib/active_record/migration.rb +1 -1
  25. data/lib/active_record/model_schema.rb +1 -1
  26. data/lib/active_record/persistence.rb +6 -7
  27. data/lib/active_record/querying.rb +2 -1
  28. data/lib/active_record/railtie.rb +1 -3
  29. data/lib/active_record/relation.rb +26 -7
  30. data/lib/active_record/relation/delegation.rb +30 -0
  31. data/lib/active_record/relation/finder_methods.rb +2 -2
  32. data/lib/active_record/relation/merger.rb +2 -2
  33. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  34. data/lib/active_record/relation/spawn_methods.rb +1 -1
  35. data/lib/active_record/scoping/named.rb +2 -0
  36. data/lib/active_record/tasks/database_tasks.rb +1 -1
  37. metadata +8 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b480ac3395548916f9d2dd47e4b26eebab5e415cf32b51e7632bad78bf22dce9
4
- data.tar.gz: 2f07a2153ae96236fcabe811139a9660273acff5bc042ed586934b4cb7207e45
3
+ metadata.gz: 38bf52e024134bc78c1daa8bf44ee21d685adcc62ddc9ded7feae3111c08a8e7
4
+ data.tar.gz: 89f9dbe14887a77a660722bb1a09ffbde6b11a4ab600b9a724458ac369548f09
5
5
  SHA512:
6
- metadata.gz: a10d5aafe0fda079ccdeba3830674496e504c20549bb271df72cc099f63cdf10765766c13e30830b2960df7527a6aa3f499856e81e1f6baff74b61221f5c301c
7
- data.tar.gz: 5509181237ce0872ecb1662b4a31cb7ef5c85b66fe9626e6bad9869e76b9649b8bb3c3f4e91bdf31aea86ae86174a6c83da2fcfc4df2622eddbb628fc0ca3d1c
6
+ metadata.gz: f0a17e48f08ba5082caa787efabf99f58bf0738de05a53f0fc4979ed27285f42f4f28e9406089f74845573f43d7a78718d5323bce8826a48d7bb673a77717055
7
+ data.tar.gz: '03572796340d73d6e9b1cfa04c1d10d84a528615e76d9e0f700af85086d4dad11c58e21ca96b8c44bddd303dd090a25e68489391046e6cd0b8cc7565d2393da8'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,110 @@
1
+ ## Rails 5.2.2 (December 04, 2018) ##
2
+
3
+ * Do not ignore the scoping with query methods in the scope block.
4
+
5
+ *Ryuta Kamizono*
6
+
7
+ * Allow aliased attributes to be used in `#update_columns` and `#update`.
8
+
9
+ *Gannon McGibbon*
10
+
11
+ * Allow spaces in postgres table names.
12
+
13
+ Fixes issue where "user post" is misinterpreted as "\"user\".\"post\"" when quoting table names with the postgres
14
+ adapter.
15
+
16
+ *Gannon McGibbon*
17
+
18
+ * Cached columns_hash fields should be excluded from ResultSet#column_types
19
+
20
+ PR #34528 addresses the inconsistent behaviour when attribute is defined for an ignored column. The following test
21
+ was passing for SQLite and MySQL, but failed for PostgreSQL:
22
+
23
+ ```ruby
24
+ class DeveloperName < ActiveRecord::Type::String
25
+ def deserialize(value)
26
+ "Developer: #{value}"
27
+ end
28
+ end
29
+
30
+ class AttributedDeveloper < ActiveRecord::Base
31
+ self.table_name = "developers"
32
+
33
+ attribute :name, DeveloperName.new
34
+
35
+ self.ignored_columns += ["name"]
36
+ end
37
+
38
+ developer = AttributedDeveloper.create
39
+ developer.update_column :name, "name"
40
+
41
+ loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
42
+ puts loaded_developer.name # should be "Developer: name" but it's just "name"
43
+ ```
44
+
45
+ *Dmitry Tsepelev*
46
+
47
+ * Values of enum are frozen, raising an error when attempting to modify them.
48
+
49
+ *Emmanuel Byrd*
50
+
51
+ * `update_columns` now correctly raises `ActiveModel::MissingAttributeError`
52
+ if the attribute does not exist.
53
+
54
+ *Sean Griffin*
55
+
56
+ * Do not use prepared statement in queries that have a large number of binds.
57
+
58
+ *Ryuta Kamizono*
59
+
60
+ * Fix query cache to load before first request.
61
+
62
+ *Eileen M. Uchitelle*
63
+
64
+ * Fix collection cache key with limit and custom select to avoid ambiguous timestamp column error.
65
+
66
+ Fixes #33056.
67
+
68
+ *Federico Martinez*
69
+
70
+ * Fix duplicated record creation when using nested attributes with `create_with`.
71
+
72
+ *Darwin Wu*
73
+
74
+ * Fix regression setting children record in parent `before_save` callback.
75
+
76
+ *Guo Xiang Tan*
77
+
78
+ * Prevent leaking of user's DB credentials on `rails db:create` failure.
79
+
80
+ *bogdanvlviv*
81
+
82
+ * Clear mutation tracker before continuing the around callbacks.
83
+
84
+ *Yuya Tanaka*
85
+
86
+ * Prevent deadlocks when waiting for connection from pool.
87
+
88
+ *Brent Wheeldon*
89
+
90
+ * Avoid extra scoping when using `Relation#update` that was causing this method to change the current scope.
91
+
92
+ *Ryuta Kamizono*
93
+
94
+ * Fix numericality validator not to be affected by custom getter.
95
+
96
+ *Ryuta Kamizono*
97
+
98
+ * Fix bulk change table ignores comment option on PostgreSQL.
99
+
100
+ *Yoshiyuki Kinjo*
101
+
102
+
103
+ ## Rails 5.2.1.1 (November 27, 2018) ##
104
+
105
+ * No changes.
106
+
107
+
1
108
  ## Rails 5.2.1 (August 07, 2018) ##
2
109
 
3
110
  * PostgreSQL: Support new relkind for partitioned tables.
@@ -31,9 +31,9 @@ module ActiveRecord
31
31
  private
32
32
 
33
33
  def exec_queries
34
- super do |r|
35
- @association.set_inverse_instance r
36
- yield r if block_given?
34
+ super do |record|
35
+ @association.set_inverse_instance_from_queries(record)
36
+ yield record if block_given?
37
37
  end
38
38
  end
39
39
  end
@@ -103,6 +103,13 @@ module ActiveRecord
103
103
  record
104
104
  end
105
105
 
106
+ def set_inverse_instance_from_queries(record)
107
+ if inverse = inverse_association_for(record)
108
+ inverse.inversed_from_queries(owner)
109
+ end
110
+ record
111
+ end
112
+
106
113
  # Remove the inverse association, if possible
107
114
  def remove_inverse_instance(record)
108
115
  if inverse = inverse_association_for(record)
@@ -114,6 +121,7 @@ module ActiveRecord
114
121
  self.target = record
115
122
  @inversed = !!record
116
123
  end
124
+ alias :inversed_from_queries :inversed_from
117
125
 
118
126
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
119
127
  # polymorphic_type field on the owner.
@@ -45,6 +45,8 @@ module ActiveRecord
45
45
  def ids_reader
46
46
  if loaded?
47
47
  target.pluck(reflection.association_primary_key)
48
+ elsif !target.empty?
49
+ load_target.pluck(reflection.association_primary_key)
48
50
  else
49
51
  @association_ids ||= scope.pluck(reflection.association_primary_key)
50
52
  end
@@ -409,9 +411,9 @@ module ActiveRecord
409
411
  end
410
412
 
411
413
  def replace_records(new_target, original_target)
412
- delete(target - new_target)
414
+ delete(difference(target, new_target))
413
415
 
414
- unless concat(new_target - target)
416
+ unless concat(difference(new_target, target))
415
417
  @target = original_target
416
418
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
417
419
  "new records could not be saved."
@@ -421,7 +423,7 @@ module ActiveRecord
421
423
  end
422
424
 
423
425
  def replace_common_records_in_memory(new_target, original_target)
424
- common_records = new_target & original_target
426
+ common_records = intersection(new_target, original_target)
425
427
  common_records.each do |record|
426
428
  skip_callbacks = true
427
429
  replace_on_target(record, @target.index(record), skip_callbacks)
@@ -130,6 +130,14 @@ module ActiveRecord
130
130
  end
131
131
  saved_successfully
132
132
  end
133
+
134
+ def difference(a, b)
135
+ a - b
136
+ end
137
+
138
+ def intersection(a, b)
139
+ a & b
140
+ end
133
141
  end
134
142
  end
135
143
  end
@@ -163,6 +163,28 @@ module ActiveRecord
163
163
  end
164
164
  end
165
165
 
166
+ def difference(a, b)
167
+ distribution = distribution(b)
168
+
169
+ a.reject { |record| mark_occurrence(distribution, record) }
170
+ end
171
+
172
+ def intersection(a, b)
173
+ distribution = distribution(b)
174
+
175
+ a.select { |record| mark_occurrence(distribution, record) }
176
+ end
177
+
178
+ def mark_occurrence(distribution, record)
179
+ distribution[record] > 0 && distribution[record] -= 1
180
+ end
181
+
182
+ def distribution(array)
183
+ array.each_with_object(Hash.new(0)) do |record, distribution|
184
+ distribution[record] += 1
185
+ end
186
+ end
187
+
166
188
  def through_records_for(record)
167
189
  attributes = construct_join_attributes(record)
168
190
  candidates = Array.wrap(through_association.target)
@@ -16,9 +16,6 @@ module ActiveRecord
16
16
 
17
17
  class_attribute :partial_writes, instance_writer: false, default: true
18
18
 
19
- after_create { changes_applied }
20
- after_update { changes_applied }
21
-
22
19
  # Attribute methods for "changed in last call to save?"
23
20
  attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
24
21
  attribute_method_prefix("saved_change_to_")
@@ -123,18 +120,26 @@ module ActiveRecord
123
120
  end
124
121
 
125
122
  private
126
- def write_attribute_without_type_cast(attr_name, _)
127
- result = super
128
- clear_attribute_change(attr_name)
123
+ def write_attribute_without_type_cast(attr_name, value)
124
+ name = attr_name.to_s
125
+ if self.class.attribute_alias?(name)
126
+ name = self.class.attribute_alias(name)
127
+ end
128
+ result = super(name, value)
129
+ clear_attribute_change(name)
129
130
  result
130
131
  end
131
132
 
132
133
  def _update_record(*)
133
- partial_writes? ? super(keys_for_partial_write) : super
134
+ affected_rows = partial_writes? ? super(keys_for_partial_write) : super
135
+ changes_applied
136
+ affected_rows
134
137
  end
135
138
 
136
139
  def _create_record(*)
137
- partial_writes? ? super(keys_for_partial_write) : super
140
+ id = partial_writes? ? super(keys_for_partial_write) : super
141
+ changes_applied
142
+ id
138
143
  end
139
144
 
140
145
  def keys_for_partial_write
@@ -392,7 +392,7 @@ module ActiveRecord
392
392
  records -= records_to_destroy
393
393
  end
394
394
 
395
- records.each_with_index do |record, index|
395
+ records.each do |record|
396
396
  next if record.destroyed?
397
397
 
398
398
  saved = true
@@ -401,11 +401,11 @@ module ActiveRecord
401
401
  if autosave
402
402
  saved = association.insert_record(record, false)
403
403
  elsif !reflection.nested?
404
+ association_saved = association.insert_record(record)
405
+
404
406
  if reflection.validate?
405
- valid = association_valid?(reflection, record, index)
406
- saved = valid ? association.insert_record(record, false) : false
407
- else
408
- association.insert_record(record)
407
+ errors.add(reflection.name) unless association_saved
408
+ saved = association_saved
409
409
  end
410
410
  end
411
411
  elsif autosave
@@ -332,7 +332,7 @@ module ActiveRecord
332
332
  _run_touch_callbacks { super }
333
333
  end
334
334
 
335
- def increment!(*, touch: nil) # :nodoc:
335
+ def increment!(attribute, by = 1, touch: nil) # :nodoc:
336
336
  touch ? _run_touch_callbacks { super } : super
337
337
  end
338
338
 
@@ -20,9 +20,9 @@ module ActiveRecord
20
20
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
21
21
 
22
22
  if collection.has_limit_or_offset?
23
- query = collection.select(column)
23
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
24
24
  subquery_alias = "subquery_for_cache_key"
25
- subquery_column = "#{subquery_alias}.#{timestamp_column}"
25
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
26
26
  subquery = query.arel.as(subquery_alias)
27
27
  arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
28
28
  else
@@ -188,7 +188,9 @@ module ActiveRecord
188
188
  t0 = Time.now
189
189
  elapsed = 0
190
190
  loop do
191
- @cond.wait(timeout - elapsed)
191
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
192
+ @cond.wait(timeout - elapsed)
193
+ end
192
194
 
193
195
  return remove if any?
194
196
 
@@ -62,6 +62,11 @@ module ActiveRecord
62
62
  def joins_per_query
63
63
  256
64
64
  end
65
+
66
+ private
67
+ def bind_params_length
68
+ 65535
69
+ end
65
70
  end
66
71
  end
67
72
  end
@@ -46,11 +46,16 @@ module ActiveRecord
46
46
  def select_all(arel, name = nil, binds = [], preparable: nil)
47
47
  arel = arel_from_relation(arel)
48
48
  sql, binds = to_sql_and_binds(arel, binds)
49
+
49
50
  if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
50
51
  preparable = false
52
+ elsif binds.length > bind_params_length
53
+ sql, binds = unprepared_statement { to_sql_and_binds(arel) }
54
+ preparable = false
51
55
  else
52
56
  preparable = visitor.preparable
53
57
  end
58
+
54
59
  if prepared_statements && preparable
55
60
  select_prepared(sql, name, binds)
56
61
  else
@@ -195,12 +195,12 @@ module ActiveRecord
195
195
  if e.path == path_to_adapter
196
196
  # We can assume that a non-builtin adapter was specified, so it's
197
197
  # either misspelled or missing from Gemfile.
198
- raise e.class, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
198
+ raise LoadError, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
199
199
 
200
200
  # Bubbled up from the adapter require. Prefix the exception message
201
201
  # with some guidance about how to address it and reraise.
202
202
  else
203
- raise e.class, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
203
+ raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
204
204
  end
205
205
  end
206
206
 
@@ -10,8 +10,17 @@ module ActiveRecord
10
10
  super
11
11
  end
12
12
 
13
- def visit_Arel_Nodes_In(*)
13
+ def visit_Arel_Nodes_In(o, collector)
14
14
  @preparable = false
15
+
16
+ if Array === o.right && !o.right.empty?
17
+ o.right.delete_if do |bind|
18
+ if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
19
+ !bind.value.boundable?
20
+ end
21
+ end
22
+ end
23
+
15
24
  super
16
25
  end
17
26
 
@@ -33,7 +33,13 @@ module ActiveRecord
33
33
 
34
34
  def cast(value)
35
35
  if value.is_a?(::String)
36
- value = @pg_decoder.decode(value)
36
+ value = begin
37
+ @pg_decoder.decode(value)
38
+ rescue TypeError
39
+ # malformed array string is treated as [], will raise in PG 2.0 gem
40
+ # this keeps a consistent implementation
41
+ []
42
+ end
37
43
  end
38
44
  type_cast_array(value, :cast)
39
45
  end
@@ -124,7 +124,7 @@ module ActiveRecord
124
124
 
125
125
  # add info on sort order (only desc order is explicitly specified, asc is the default)
126
126
  # and non-default opclasses
127
- expressions.scan(/(?<column>\w+)\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
127
+ expressions.scan(/(?<column>\w+)"?\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
128
128
  opclasses[column] = opclass.to_sym if opclass
129
129
  if nulls
130
130
  orders[column] = [desc, nulls].compact.join(" ")
@@ -700,6 +700,11 @@ module ActiveRecord
700
700
  sql
701
701
  end
702
702
 
703
+ def add_column_for_alter(table_name, column_name, type, options = {})
704
+ return super unless options.key?(:comment)
705
+ [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
706
+ end
707
+
703
708
  def change_column_for_alter(table_name, column_name, type, options = {})
704
709
  sqls = [change_column_sql(table_name, column_name, type, options)]
705
710
  sqls << change_column_default_for_alter(table_name, column_name, options[:default]) if options.key?(:default)
@@ -708,7 +713,6 @@ module ActiveRecord
708
713
  sqls
709
714
  end
710
715
 
711
-
712
716
  # Changes the default value of a table column.
713
717
  def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
714
718
  column = column_for(table_name, column_name)
@@ -68,7 +68,7 @@ module ActiveRecord
68
68
  # * <tt>"schema_name".table_name</tt>
69
69
  # * <tt>"schema.name"."table name"</tt>
70
70
  def extract_schema_qualified_name(string)
71
- schema, table = string.scan(/[^".\s]+|"[^"]*"/)
71
+ schema, table = string.scan(/[^".]+|"[^"]*"/)
72
72
  if table.nil?
73
73
  table = schema
74
74
  schema = nil
@@ -4,6 +4,14 @@
4
4
  gem "pg", ">= 0.18", "< 2.0"
5
5
  require "pg"
6
6
 
7
+ # Use async_exec instead of exec_params on pg versions before 1.1
8
+ class ::PG::Connection
9
+ unless self.public_method_defined?(:async_exec_params)
10
+ remove_method :exec_params
11
+ alias exec_params async_exec
12
+ end
13
+ end
14
+
7
15
  require "active_record/connection_adapters/abstract_adapter"
8
16
  require "active_record/connection_adapters/statement_pool"
9
17
  require "active_record/connection_adapters/postgresql/column"
@@ -600,7 +608,7 @@ module ActiveRecord
600
608
  type_casted_binds = type_casted_binds(binds)
601
609
  log(sql, name, binds, type_casted_binds) do
602
610
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
603
- @connection.async_exec(sql, type_casted_binds)
611
+ @connection.exec_params(sql, type_casted_binds)
604
612
  end
605
613
  end
606
614
  end
@@ -201,6 +201,7 @@ module ActiveRecord
201
201
  klass.scope value_method_name, -> { where(attr => value) }
202
202
  end
203
203
  end
204
+ enum_values.freeze
204
205
  end
205
206
  end
206
207
 
@@ -126,7 +126,7 @@ module ActiveRecord
126
126
  To resolve this issue, change the type of the `#{foreign_key}` column on `#{table}` to be :integer. (For example `t.integer #{foreign_key}`).
127
127
  EOM
128
128
  else
129
- msg = <<-EOM
129
+ msg = <<-EOM.strip_heredoc
130
130
  There is a mismatch between the foreign key and primary key column types.
131
131
  Verify that the foreign key column type and the primary key of the associated table match types.
132
132
  EOM
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 5
11
11
  MINOR = 2
12
- TINY = 1
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -1163,7 +1163,7 @@ module ActiveRecord
1163
1163
 
1164
1164
  def migrations_path=(path)
1165
1165
  ActiveSupport::Deprecation.warn \
1166
- "ActiveRecord::Migrator.migrations_paths= is now deprecated and will be removed in Rails 6.0." \
1166
+ "`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
1167
1167
  "You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
1168
1168
  self.migrations_paths = [path]
1169
1169
  end
@@ -375,7 +375,7 @@ module ActiveRecord
375
375
  # default values when instantiating the Active Record object for this table.
376
376
  def column_defaults
377
377
  load_schema
378
- @column_defaults ||= _default_attributes.to_hash
378
+ @column_defaults ||= _default_attributes.deep_dup.to_hash
379
379
  end
380
380
 
381
381
  def _default_attributes # :nodoc:
@@ -97,13 +97,11 @@ module ActiveRecord
97
97
  # When running callbacks is not needed for each record update,
98
98
  # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
99
99
  # for updating all records in a single query.
100
- def update(id = :all, attributes)
100
+ def update(id, attributes)
101
101
  if id.is_a?(Array)
102
102
  id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
103
103
  object.update(attributes[idx])
104
104
  }
105
- elsif id == :all
106
- all.each { |record| record.update(attributes) }
107
105
  else
108
106
  if ActiveRecord::Base === id
109
107
  raise ArgumentError,
@@ -473,15 +471,16 @@ module ActiveRecord
473
471
  verify_readonly_attribute(key.to_s)
474
472
  end
475
473
 
474
+ id_in_database = self.id_in_database
475
+ attributes.each do |k, v|
476
+ write_attribute_without_type_cast(k, v)
477
+ end
478
+
476
479
  affected_rows = self.class._update_record(
477
480
  attributes,
478
481
  self.class.primary_key => id_in_database
479
482
  )
480
483
 
481
- attributes.each do |k, v|
482
- write_attribute_without_type_cast(k, v)
483
- end
484
-
485
484
  affected_rows == 1
486
485
  end
487
486
 
@@ -40,7 +40,8 @@ module ActiveRecord
40
40
  def find_by_sql(sql, binds = [], preparable: nil, &block)
41
41
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
42
42
  column_types = result_set.column_types.dup
43
- columns_hash.each_key { |k| column_types.delete k }
43
+ cached_columns_hash = connection.schema_cache.columns_hash(table_name)
44
+ cached_columns_hash.each_key { |k| column_types.delete k }
44
45
  message_bus = ActiveSupport::Notifications.instrumenter
45
46
 
46
47
  payload = {
@@ -169,9 +169,7 @@ end_warning
169
169
  end
170
170
 
171
171
  initializer "active_record.set_executor_hooks" do
172
- ActiveSupport.on_load(:active_record) do
173
- ActiveRecord::QueryCache.install_executor_hooks
174
- end
172
+ ActiveRecord::QueryCache.install_executor_hooks
175
173
  end
176
174
 
177
175
  initializer "active_record.add_watchable_files" do |app|
@@ -54,7 +54,7 @@ module ActiveRecord
54
54
  # user = users.new { |user| user.name = 'Oscar' }
55
55
  # user.name # => Oscar
56
56
  def new(attributes = nil, &block)
57
- scoping { klass.new(scope_for_create(attributes), &block) }
57
+ scoping { klass.new(values_for_create(attributes), &block) }
58
58
  end
59
59
 
60
60
  alias build new
@@ -82,7 +82,7 @@ module ActiveRecord
82
82
  if attributes.is_a?(Array)
83
83
  attributes.collect { |attr| create(attr, &block) }
84
84
  else
85
- scoping { klass.create(scope_for_create(attributes), &block) }
85
+ scoping { klass.create(values_for_create(attributes), &block) }
86
86
  end
87
87
  end
88
88
 
@@ -96,7 +96,7 @@ module ActiveRecord
96
96
  if attributes.is_a?(Array)
97
97
  attributes.collect { |attr| create!(attr, &block) }
98
98
  else
99
- scoping { klass.create!(scope_for_create(attributes), &block) }
99
+ scoping { klass.create!(values_for_create(attributes), &block) }
100
100
  end
101
101
  end
102
102
 
@@ -337,6 +337,14 @@ module ActiveRecord
337
337
  @klass.connection.update stmt, "#{@klass} Update All"
338
338
  end
339
339
 
340
+ def update(id = :all, attributes) # :nodoc:
341
+ if id == :all
342
+ each { |record| record.update(attributes) }
343
+ else
344
+ klass.update(id, attributes)
345
+ end
346
+ end
347
+
340
348
  # Destroys the records by instantiating each
341
349
  # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
342
350
  # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
@@ -456,10 +464,8 @@ module ActiveRecord
456
464
  where_clause.to_h(relation_table_name)
457
465
  end
458
466
 
459
- def scope_for_create(attributes = nil)
460
- scope = where_values_hash.merge!(create_with_value.stringify_keys)
461
- scope.merge!(attributes) if attributes
462
- scope
467
+ def scope_for_create
468
+ where_values_hash.merge!(create_with_value.stringify_keys)
463
469
  end
464
470
 
465
471
  # Returns true if relation needs eager loading.
@@ -606,5 +612,18 @@ module ActiveRecord
606
612
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
607
613
  string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
608
614
  end
615
+
616
+ def values_for_create(attributes = nil)
617
+ result = attributes ? where_values_hash.merge!(attributes) : where_values_hash
618
+
619
+ # NOTE: if there are same keys in both create_with and result, create_with should be used.
620
+ # This is to make sure nested attributes don't get passed to the klass.new,
621
+ # while keeping the precedence of the duplicate keys in create_with.
622
+ create_with_value.stringify_keys.each do |k, v|
623
+ result[k] = v if result.key?(k)
624
+ end
625
+
626
+ result
627
+ end
609
628
  end
610
629
  end
@@ -17,6 +17,7 @@ module ActiveRecord
17
17
  delegate = Class.new(klass) {
18
18
  include ClassSpecificRelation
19
19
  }
20
+ include_relation_methods(delegate)
20
21
  mangled_name = klass.name.gsub("::".freeze, "_".freeze)
21
22
  const_set mangled_name, delegate
22
23
  private_constant mangled_name
@@ -29,6 +30,35 @@ module ActiveRecord
29
30
  child_class.initialize_relation_delegate_cache
30
31
  super
31
32
  end
33
+
34
+ protected
35
+ def include_relation_methods(delegate)
36
+ superclass.include_relation_methods(delegate) unless base_class == self
37
+ delegate.include generated_relation_methods
38
+ end
39
+
40
+ private
41
+ def generated_relation_methods
42
+ @generated_relation_methods ||= Module.new.tap do |mod|
43
+ mod_name = "GeneratedRelationMethods"
44
+ const_set mod_name, mod
45
+ private_constant mod_name
46
+ end
47
+ end
48
+
49
+ def generate_relation_method(method)
50
+ if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
51
+ generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
+ def #{method}(*args, &block)
53
+ scoping { klass.#{method}(*args, &block) }
54
+ end
55
+ RUBY
56
+ else
57
+ generated_relation_methods.send(:define_method, method) do |*args, &block|
58
+ scoping { klass.public_send(method, *args, &block) }
59
+ end
60
+ end
61
+ end
32
62
  end
33
63
 
34
64
  extend ActiveSupport::Concern
@@ -363,7 +363,7 @@ module ActiveRecord
363
363
 
364
364
  case conditions
365
365
  when Array, Hash
366
- relation.where!(conditions)
366
+ relation.where!(conditions) unless conditions.empty?
367
367
  else
368
368
  relation.where!(primary_key => conditions) unless conditions == :none
369
369
  end
@@ -417,7 +417,7 @@ module ActiveRecord
417
417
  raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
418
418
 
419
419
  expects_array = ids.first.kind_of?(Array)
420
- return ids.first if expects_array && ids.first.empty?
420
+ return [] if expects_array && ids.first.empty?
421
421
 
422
422
  ids = ids.flatten.compact.uniq
423
423
 
@@ -156,10 +156,10 @@ module ActiveRecord
156
156
  def merge_multi_values
157
157
  if other.reordering_value
158
158
  # override any order specified in the original relation
159
- relation.reorder! other.order_values
159
+ relation.reorder!(*other.order_values)
160
160
  elsif other.order_values.any?
161
161
  # merge in order_values from relation
162
- relation.order! other.order_values
162
+ relation.order!(*other.order_values)
163
163
  end
164
164
 
165
165
  extensions = other.extensions - relation.extensions
@@ -19,10 +19,10 @@ module ActiveRecord
19
19
  when 0 then NullPredicate
20
20
  when 1 then predicate_builder.build(attribute, values.first)
21
21
  else
22
- bind_values = values.map do |v|
22
+ values.map! do |v|
23
23
  predicate_builder.build_bind_attribute(attribute.name, v)
24
24
  end
25
- attribute.in(bind_values)
25
+ values.empty? ? NullPredicate : attribute.in(values)
26
26
  end
27
27
 
28
28
  unless nils.empty?
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  module SpawnMethods
9
9
  # This is overridden by Associations::CollectionProxy
10
10
  def spawn #:nodoc:
11
- clone
11
+ @delegate_to_klass ? klass.all : clone
12
12
  end
13
13
 
14
14
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
@@ -195,6 +195,8 @@ module ActiveRecord
195
195
  scope
196
196
  end
197
197
  end
198
+
199
+ generate_relation_method(name)
198
200
  end
199
201
 
200
202
  private
@@ -122,7 +122,7 @@ module ActiveRecord
122
122
  $stderr.puts "Database '#{configuration['database']}' already exists"
123
123
  rescue Exception => error
124
124
  $stderr.puts error
125
- $stderr.puts "Couldn't create database for #{configuration.inspect}"
125
+ $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
126
126
  raise
127
127
  end
128
128
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.1
4
+ version: 5.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-07 00:00:00.000000000 Z
11
+ date: 2018-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.2.1
19
+ version: 5.2.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.2.1
26
+ version: 5.2.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 5.2.1
33
+ version: 5.2.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 5.2.1
40
+ version: 5.2.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: arel
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -307,8 +307,8 @@ homepage: http://rubyonrails.org
307
307
  licenses:
308
308
  - MIT
309
309
  metadata:
310
- source_code_uri: https://github.com/rails/rails/tree/v5.2.1/activerecord
311
- changelog_uri: https://github.com/rails/rails/blob/v5.2.1/activerecord/CHANGELOG.md
310
+ source_code_uri: https://github.com/rails/rails/tree/v5.2.2/activerecord
311
+ changelog_uri: https://github.com/rails/rails/blob/v5.2.2/activerecord/CHANGELOG.md
312
312
  post_install_message:
313
313
  rdoc_options:
314
314
  - "--main"