activerecord 4.2.11.3 → 5.0.7.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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord::Associations
2
- module ForeignAssociation
2
+ module ForeignAssociation # :nodoc:
3
3
  def foreign_key_present?
4
4
  if reflection.klass.primary_key
5
5
  owner.attribute_present?(reflection.active_record_primary_key)
@@ -15,9 +15,16 @@ module ActiveRecord
15
15
 
16
16
  when :restrict_with_error
17
17
  unless empty?
18
- record = klass.human_attribute_name(reflection.name).downcase
19
- owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record)
20
- false
18
+ record = owner.class.human_attribute_name(reflection.name).downcase
19
+ message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil
20
+ if message
21
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
22
+ The error key `:'restrict_dependent_destroy.many'` has been deprecated and will be removed in Rails 5.1.
23
+ Please use `:'restrict_dependent_destroy.has_many'` instead.
24
+ MESSAGE
25
+ end
26
+ owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
27
+ throw(:abort)
21
28
  end
22
29
 
23
30
  else
@@ -33,17 +40,11 @@ module ActiveRecord
33
40
 
34
41
  def insert_record(record, validate = true, raise = false)
35
42
  set_owner_attributes(record)
36
- set_inverse_instance(record)
37
-
38
- if raise
39
- record.save!(:validate => validate)
40
- else
41
- record.save(:validate => validate)
42
- end
43
+ super
43
44
  end
44
45
 
45
46
  def empty?
46
- if has_cached_counter?
47
+ if reflection.has_cached_counter?
47
48
  size.zero?
48
49
  else
49
50
  super
@@ -66,8 +67,8 @@ module ActiveRecord
66
67
  # If the collection is empty the target is set to an empty array and
67
68
  # the loaded flag is set to true as well.
68
69
  def count_records
69
- count = if has_cached_counter?
70
- owner._read_attribute cached_counter_attribute_name
70
+ count = if reflection.has_cached_counter?
71
+ owner._read_attribute reflection.counter_cache_column
71
72
  else
72
73
  scope.count
73
74
  end
@@ -80,78 +81,20 @@ module ActiveRecord
80
81
  [association_scope.limit_value, count].compact.min
81
82
  end
82
83
 
83
-
84
- # Returns whether a counter cache should be used for this association.
85
- #
86
- # The counter_cache option must be given on either the owner or inverse
87
- # association, and the column must be present on the owner.
88
- def has_cached_counter?(reflection = reflection())
89
- if reflection.options[:counter_cache] || (inverse = inverse_which_updates_counter_cache(reflection)) && inverse.options[:counter_cache]
90
- owner.attribute_present?(cached_counter_attribute_name(reflection))
91
- end
92
- end
93
-
94
- def cached_counter_attribute_name(reflection = reflection())
95
- if reflection.options[:counter_cache]
96
- reflection.options[:counter_cache].to_s
97
- else
98
- "#{reflection.name}_count"
99
- end
100
- end
101
-
102
84
  def update_counter(difference, reflection = reflection())
103
- update_counter_in_database(difference, reflection)
104
- update_counter_in_memory(difference, reflection)
105
- end
106
-
107
- def update_counter_in_database(difference, reflection = reflection())
108
- if has_cached_counter?(reflection)
109
- counter = cached_counter_attribute_name(reflection)
110
- owner.class.update_counters(owner.id, counter => difference)
85
+ if reflection.has_cached_counter?
86
+ owner.increment!(reflection.counter_cache_column, difference)
111
87
  end
112
88
  end
113
89
 
114
90
  def update_counter_in_memory(difference, reflection = reflection())
115
- if counter_must_be_updated_by_has_many?(reflection)
116
- counter = cached_counter_attribute_name(reflection)
117
- owner[counter] += difference
118
- owner.send(:clear_attribute_changes, counter) # eww
91
+ if reflection.counter_must_be_updated_by_has_many?
92
+ counter = reflection.counter_cache_column
93
+ owner.increment(counter, difference)
94
+ owner.send(:clear_attribute_change, counter) # eww
119
95
  end
120
96
  end
121
97
 
122
- # This shit is nasty. We need to avoid the following situation:
123
- #
124
- # * An associated record is deleted via record.destroy
125
- # * Hence the callbacks run, and they find a belongs_to on the record with a
126
- # :counter_cache options which points back at our owner. So they update the
127
- # counter cache.
128
- # * In which case, we must make sure to *not* update the counter cache, or else
129
- # it will be decremented twice.
130
- #
131
- # Hence this method.
132
- def inverse_which_updates_counter_cache(reflection = reflection())
133
- counter_name = cached_counter_attribute_name(reflection)
134
- inverse_which_updates_counter_named(counter_name, reflection)
135
- end
136
- alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
137
-
138
- def inverse_which_updates_counter_named(counter_name, reflection)
139
- reflection.klass._reflections.values.find { |inverse_reflection|
140
- inverse_reflection.belongs_to? &&
141
- inverse_reflection.counter_cache_column == counter_name
142
- }
143
- end
144
- alias inverse_updates_counter_named? inverse_which_updates_counter_named
145
-
146
- def inverse_updates_counter_in_memory?(reflection)
147
- inverse = inverse_which_updates_counter_cache(reflection)
148
- inverse && inverse == reflection.inverse_of
149
- end
150
-
151
- def counter_must_be_updated_by_has_many?(reflection)
152
- !inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
153
- end
154
-
155
98
  def delete_count(method, scope)
156
99
  if method == :delete_all
157
100
  scope.delete_all
@@ -169,7 +112,7 @@ module ActiveRecord
169
112
  def delete_records(records, method)
170
113
  if method == :destroy
171
114
  records.each(&:destroy!)
172
- update_counter(-records.length) unless inverse_updates_counter_cache?
115
+ update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
173
116
  else
174
117
  scope = self.scope.where(reflection.klass.primary_key => records)
175
118
  update_counter(-delete_count(method, scope))
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/filters'
2
-
3
1
  module ActiveRecord
4
2
  # = Active Record Has Many Through Association
5
3
  module Associations
@@ -13,21 +11,6 @@ module ActiveRecord
13
11
  @through_association = nil
14
12
  end
15
13
 
16
- # Returns the size of the collection by executing a SELECT COUNT(*) query
17
- # if the collection hasn't been loaded, and by calling collection.size if
18
- # it has. If the collection will likely have a size greater than zero,
19
- # and if fetching the collection will be needed afterwards, one less
20
- # SELECT query will be generated by using #length instead.
21
- def size
22
- if has_cached_counter?
23
- owner._read_attribute cached_counter_attribute_name(reflection)
24
- elsif loaded?
25
- target.size
26
- else
27
- super
28
- end
29
- end
30
-
31
14
  def concat(*records)
32
15
  unless owner.new_record?
33
16
  records.flatten.each do |record|
@@ -55,25 +38,12 @@ module ActiveRecord
55
38
  def insert_record(record, validate = true, raise = false)
56
39
  ensure_not_nested
57
40
 
58
- if record.new_record?
59
- if raise
60
- record.save!(:validate => validate)
61
- else
62
- return unless record.save(:validate => validate)
63
- end
41
+ if record.new_record? || record.changed?
42
+ return unless super
64
43
  end
65
44
 
66
45
  save_through_record(record)
67
- if has_cached_counter? && !through_reflection_updates_counter_cache?
68
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
69
- Automatic updating of counter caches on through associations has been
70
- deprecated, and will be removed in Rails 5. Instead, please set the
71
- appropriate `counter_cache` options on the `has_many` and `belongs_to`
72
- for your associations to #{through_reflection.name}.
73
- MSG
74
46
 
75
- update_counter_in_database(1)
76
- end
77
47
  record
78
48
  end
79
49
 
@@ -143,7 +113,7 @@ module ActiveRecord
143
113
  def update_through_counter?(method)
144
114
  case method
145
115
  when :destroy
146
- !inverse_updates_counter_cache?(through_reflection)
116
+ !through_reflection.inverse_updates_counter_cache?
147
117
  when :nullify
148
118
  false
149
119
  else
@@ -166,17 +136,15 @@ module ActiveRecord
166
136
  if scope.klass.primary_key
167
137
  count = scope.destroy_all.length
168
138
  else
169
- scope.each do |record|
170
- record._run_destroy_callbacks
171
- end
139
+ scope.each(&:_run_destroy_callbacks)
172
140
 
173
141
  arel = scope.arel
174
142
 
175
- stmt = Arel::DeleteManager.new arel.engine
143
+ stmt = Arel::DeleteManager.new
176
144
  stmt.from scope.klass.arel_table
177
145
  stmt.wheres = arel.constraints
178
146
 
179
- count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
147
+ count = scope.klass.connection.delete(stmt, 'SQL', scope.bound_attributes)
180
148
  end
181
149
  when :nullify
182
150
  count = scope.update_all(source_reflection.foreign_key => nil)
@@ -233,15 +201,6 @@ module ActiveRecord
233
201
  def invertible_for?(record)
234
202
  false
235
203
  end
236
-
237
- def has_cached_counter?(reflection = reflection())
238
- owner.attribute_present?(cached_counter_attribute_name(reflection))
239
- end
240
-
241
- def through_reflection_updates_counter_cache?
242
- counter_name = cached_counter_attribute_name
243
- inverse_updates_counter_named?(counter_name, through_reflection)
244
- end
245
204
  end
246
205
  end
247
206
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
- # = Active Record Belongs To Has One Association
2
+ # = Active Record Has One Association
3
3
  module Associations
4
4
  class HasOneAssociation < SingularAssociation #:nodoc:
5
5
  include ForeignAssociation
@@ -11,9 +11,16 @@ module ActiveRecord
11
11
 
12
12
  when :restrict_with_error
13
13
  if load_target
14
- record = klass.human_attribute_name(reflection.name).downcase
15
- owner.errors.add(:base, :"restrict_dependent_destroy.one", record: record)
16
- false
14
+ record = owner.class.human_attribute_name(reflection.name).downcase
15
+ message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.one', record: record, raise: true) rescue nil
16
+ if message
17
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
18
+ The error key `:'restrict_dependent_destroy.one'` has been deprecated and will be removed in Rails 5.1.
19
+ Please use `:'restrict_dependent_destroy.has_one'` instead.
20
+ MESSAGE
21
+ end
22
+ owner.errors.add(:base, message || :'restrict_dependent_destroy.has_one', record: record)
23
+ throw(:abort)
17
24
  end
18
25
 
19
26
  else
@@ -58,7 +65,7 @@ module ActiveRecord
58
65
  when :destroy
59
66
  target.destroy
60
67
  when :nullify
61
- target.update_columns(reflection.foreign_key => nil)
68
+ target.update_columns(reflection.foreign_key => nil) if target.persisted?
62
69
  end
63
70
  end
64
71
  end
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  end
21
21
 
22
22
  def columns
23
- @tables.flat_map { |t| t.column_aliases }
23
+ @tables.flat_map(&:column_aliases)
24
24
  end
25
25
 
26
26
  # An array of [column_name, alias] pairs for the table
@@ -32,7 +32,7 @@ module ActiveRecord
32
32
  @alias_cache[node][column]
33
33
  end
34
34
 
35
- class Table < Struct.new(:node, :columns)
35
+ class Table < Struct.new(:node, :columns) # :nodoc:
36
36
  def table
37
37
  Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
38
38
  end
@@ -93,8 +93,7 @@ module ActiveRecord
93
93
  # joins # => []
94
94
  #
95
95
  def initialize(base, associations, joins)
96
- @alias_tracker = AliasTracker.create(base.connection, joins)
97
- @alias_tracker.aliased_table_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1
96
+ @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins, base.type_caster)
98
97
  tree = self.class.make_tree associations
99
98
  @join_root = JoinBase.new base, build(tree, base)
100
99
  @join_root.children.each { |child| construct_tables! @join_root, child }
@@ -104,9 +103,14 @@ module ActiveRecord
104
103
  join_root.drop(1).map!(&:reflection)
105
104
  end
106
105
 
107
- def join_constraints(outer_joins)
106
+ def join_constraints(outer_joins, join_type)
108
107
  joins = join_root.children.flat_map { |child|
109
- make_inner_joins join_root, child
108
+
109
+ if join_type == Arel::Nodes::OuterJoin
110
+ make_left_outer_joins join_root, child
111
+ else
112
+ make_inner_joins join_root, child
113
+ end
110
114
  }
111
115
 
112
116
  joins.concat outer_joins.flat_map { |oj|
@@ -132,9 +136,9 @@ module ActiveRecord
132
136
  def instantiate(result_set, aliases)
133
137
  primary_key = aliases.column_alias(join_root, join_root.primary_key)
134
138
 
135
- seen = Hash.new { |h,parent_klass|
136
- h[parent_klass] = Hash.new { |i,parent_id|
137
- i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
139
+ seen = Hash.new { |i, object_id|
140
+ i[object_id] = Hash.new { |j, child_class|
141
+ j[child_class] = {}
138
142
  }
139
143
  }
140
144
 
@@ -177,6 +181,14 @@ module ActiveRecord
177
181
  [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
178
182
  end
179
183
 
184
+ def make_left_outer_joins(parent, child)
185
+ tables = child.tables
186
+ join_type = Arel::Nodes::OuterJoin
187
+ info = make_constraints parent, child, tables, join_type
188
+
189
+ [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
190
+ end
191
+
180
192
  def make_inner_joins(parent, child)
181
193
  tables = child.tables
182
194
  join_type = Arel::Nodes::InnerJoin
@@ -216,7 +228,7 @@ module ActiveRecord
216
228
 
217
229
  def find_reflection(klass, name)
218
230
  klass._reflect_on_association(name) or
219
- raise ConfigurationError, "Association named '#{ name }' was not found on #{ klass.name }; perhaps you misspelled it?"
231
+ raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
220
232
  end
221
233
 
222
234
  def build(associations, base_klass)
@@ -235,18 +247,15 @@ module ActiveRecord
235
247
 
236
248
  def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
237
249
  return if ar_parent.nil?
238
- primary_id = ar_parent.id
239
250
 
240
251
  parent.children.each do |node|
241
252
  if node.reflection.collection?
242
253
  other = ar_parent.association(node.reflection.name)
243
254
  other.loaded!
244
- else
245
- if ar_parent.association_cache.key?(node.reflection.name)
246
- model = ar_parent.association(node.reflection.name).target
247
- construct(model, node, row, rs, seen, model_cache, aliases)
248
- next
249
- end
255
+ elsif ar_parent.association_cached?(node.reflection.name)
256
+ model = ar_parent.association(node.reflection.name).target
257
+ construct(model, node, row, rs, seen, model_cache, aliases)
258
+ next
250
259
  end
251
260
 
252
261
  key = aliases.column_alias(node, node.primary_key)
@@ -257,30 +266,37 @@ module ActiveRecord
257
266
  next
258
267
  end
259
268
 
260
- model = seen[parent.base_klass][primary_id][node.base_klass][id]
269
+ model = seen[ar_parent.object_id][node.base_klass][id]
261
270
 
262
271
  if model
263
272
  construct(model, node, row, rs, seen, model_cache, aliases)
264
273
  else
265
274
  model = construct_model(ar_parent, node, row, model_cache, id, aliases)
266
- seen[parent.base_klass][primary_id][node.base_klass][id] = model
275
+
276
+ if node.reflection.scope_for(node.base_klass).readonly_value
277
+ model.readonly!
278
+ end
279
+
280
+ seen[ar_parent.object_id][node.base_klass][id] = model
267
281
  construct(model, node, row, rs, seen, model_cache, aliases)
268
282
  end
269
283
  end
270
284
  end
271
285
 
272
286
  def construct_model(record, node, row, model_cache, id, aliases)
273
- model = model_cache[node][id] ||= node.instantiate(row,
274
- aliases.column_aliases(node))
275
287
  other = record.association(node.reflection.name)
276
288
 
289
+ model = model_cache[node][id] ||=
290
+ node.instantiate(row, aliases.column_aliases(node)) do |m|
291
+ other.set_inverse_instance(m)
292
+ end
293
+
277
294
  if node.reflection.collection?
278
295
  other.target.push(model)
279
296
  else
280
297
  other.target = model
281
298
  end
282
299
 
283
- other.set_inverse_instance(model)
284
300
  model
285
301
  end
286
302
  end
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
 
26
26
  def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
27
27
  joins = []
28
- bind_values = []
28
+ binds = []
29
29
  tables = tables.reverse
30
30
 
31
31
  scope_chain_index = 0
@@ -43,29 +43,31 @@ module ActiveRecord
43
43
 
44
44
  constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
45
45
 
46
+ predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
46
47
  scope_chain_items = scope_chain[scope_chain_index].map do |item|
47
48
  if item.is_a?(Relation)
48
49
  item
49
50
  else
50
- ActiveRecord::Relation.create(klass, table).instance_exec(node, &item)
51
+ ActiveRecord::Relation.create(klass, table, predicate_builder)
52
+ .instance_exec(node, &item)
51
53
  end
52
54
  end
53
55
  scope_chain_index += 1
54
56
 
57
+ relation = ActiveRecord::Relation.create(klass, table, predicate_builder)
58
+ current_scope = klass.current_scope
59
+
55
60
  klass_scope =
56
- if klass.current_scope && klass.current_scope.values.blank?
57
- klass.unscoped
61
+ if current_scope && current_scope.empty_scope?
62
+ relation
58
63
  else
59
- klass.send(:build_default_scope, ActiveRecord::Relation.create(klass, table))
64
+ klass.send(:build_default_scope, relation)
60
65
  end
61
- scope_chain_items.concat [klass_scope].compact
62
66
 
63
- rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
64
- left.merge right
65
- end
67
+ rel = scope_chain_items.inject(klass_scope || scope_chain_items.shift, &:merge!)
66
68
 
67
69
  if rel && !rel.arel.constraints.empty?
68
- bind_values.concat rel.bind_values
70
+ binds += rel.bound_attributes
69
71
  constraint = constraint.and rel.arel.constraints
70
72
  end
71
73
 
@@ -73,9 +75,8 @@ module ActiveRecord
73
75
  value = foreign_klass.base_class.name
74
76
  column = klass.columns_hash[reflection.type.to_s]
75
77
 
76
- substitute = klass.connection.substitute_at(column)
77
- bind_values.push [column, value]
78
- constraint = constraint.and table[reflection.type].eq substitute
78
+ binds << Relation::QueryAttribute.new(column.name, value, klass.type_for_attribute(column.name))
79
+ constraint = constraint.and klass.arel_attribute(reflection.type, table).eq(Arel::Nodes::BindParam.new)
79
80
  end
80
81
 
81
82
  joins << table.create_join(table, table.create_on(constraint), join_type)
@@ -84,7 +85,7 @@ module ActiveRecord
84
85
  foreign_table, foreign_klass = table, klass
85
86
  end
86
87
 
87
- JoinInformation.new joins, bind_values
88
+ JoinInformation.new joins, binds
88
89
  end
89
90
 
90
91
  # Builds equality condition.