activerecord 4.2.0 → 5.0.0

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  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/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -1,14 +1,14 @@
1
1
  module ActiveRecord
2
2
  module ConnectionHandling
3
- RAILS_ENV = -> { (Rails.env if defined?(Rails)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
3
+ RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
4
4
  DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
5
5
 
6
6
  # Establishes the connection to the database. Accepts a hash as input where
7
7
  # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
8
- # example for regular databases (MySQL, Postgresql, etc):
8
+ # example for regular databases (MySQL, PostgreSQL, etc):
9
9
  #
10
10
  # ActiveRecord::Base.establish_connection(
11
- # adapter: "mysql",
11
+ # adapter: "mysql2",
12
12
  # host: "localhost",
13
13
  # username: "myuser",
14
14
  # password: "mypass",
@@ -35,26 +35,30 @@ module ActiveRecord
35
35
  # "postgres://myuser:mypass@localhost/somedatabase"
36
36
  # )
37
37
  #
38
- # In case <tt>ActiveRecord::Base.configurations</tt> is set (Rails
39
- # automatically loads the contents of config/database.yml into it),
38
+ # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
39
+ # is set (Rails automatically loads the contents of config/database.yml into it),
40
40
  # a symbol can also be given as argument, representing a key in the
41
41
  # configuration hash:
42
42
  #
43
43
  # ActiveRecord::Base.establish_connection(:production)
44
44
  #
45
- # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
45
+ # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
46
46
  # may be returned on an error.
47
47
  def establish_connection(spec = nil)
48
+ raise RuntimeError, "Anonymous class is not allowed." unless name
49
+
48
50
  spec ||= DEFAULT_ENV.call.to_sym
49
51
  resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
50
- spec = resolver.spec(spec)
52
+ # TODO: uses name on establish_connection, for backwards compatibility
53
+ spec = resolver.spec(spec, self == Base ? "primary" : name)
51
54
 
52
55
  unless respond_to?(spec.adapter_method)
53
56
  raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
54
57
  end
55
58
 
56
- remove_connection
57
- connection_handler.establish_connection self, spec
59
+ remove_connection(spec.name)
60
+ self.connection_specification_name = spec.name
61
+ connection_handler.establish_connection spec
58
62
  end
59
63
 
60
64
  class MergeAndResolveDefaultUrlConfig # :nodoc:
@@ -87,8 +91,19 @@ module ActiveRecord
87
91
  retrieve_connection
88
92
  end
89
93
 
94
+ attr_writer :connection_specification_name
95
+
96
+ # Return the specification id from this class otherwise look it up
97
+ # in the parent.
98
+ def connection_specification_name
99
+ if !defined?(@connection_specification_name) || @connection_specification_name.nil?
100
+ return self == Base ? "primary" : superclass.connection_specification_name
101
+ end
102
+ @connection_specification_name
103
+ end
104
+
90
105
  def connection_id
91
- ActiveRecord::RuntimeRegistry.connection_id
106
+ ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
92
107
  end
93
108
 
94
109
  def connection_id=(connection_id)
@@ -106,20 +121,28 @@ module ActiveRecord
106
121
  end
107
122
 
108
123
  def connection_pool
109
- connection_handler.retrieve_connection_pool(self) or raise ConnectionNotEstablished
124
+ connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
110
125
  end
111
126
 
112
127
  def retrieve_connection
113
- connection_handler.retrieve_connection(self)
128
+ connection_handler.retrieve_connection(connection_specification_name)
114
129
  end
115
130
 
116
131
  # Returns +true+ if Active Record is connected.
117
132
  def connected?
118
- connection_handler.connected?(self)
133
+ connection_handler.connected?(connection_specification_name)
119
134
  end
120
135
 
121
- def remove_connection(klass = self)
122
- connection_handler.remove_connection(klass)
136
+ def remove_connection(name = nil)
137
+ name ||= @connection_specification_name if defined?(@connection_specification_name)
138
+ # if removing a connection that have a pool, we reset the
139
+ # connection_specification_name so it will use the parent
140
+ # pool.
141
+ if connection_handler.retrieve_connection_pool(name)
142
+ self.connection_specification_name = nil
143
+ end
144
+
145
+ connection_handler.remove_connection(name)
123
146
  end
124
147
 
125
148
  def clear_cache! # :nodoc:
@@ -70,6 +70,14 @@ module ActiveRecord
70
70
  mattr_accessor :schema_format, instance_writer: false
71
71
  self.schema_format = :ruby
72
72
 
73
+ ##
74
+ # :singleton-method:
75
+ # Specifies if an error should be raised on query limit or order being
76
+ # ignored when doing batch queries. Useful in applications where the
77
+ # limit or scope being ignored is error-worthy, rather than a warning.
78
+ mattr_accessor :error_on_ignored_order_or_limit, instance_writer: false
79
+ self.error_on_ignored_order_or_limit = false
80
+
73
81
  ##
74
82
  # :singleton-method:
75
83
  # Specify whether or not to use timestamps for migration versions
@@ -85,17 +93,30 @@ module ActiveRecord
85
93
  mattr_accessor :dump_schema_after_migration, instance_writer: false
86
94
  self.dump_schema_after_migration = true
87
95
 
96
+ ##
97
+ # :singleton-method:
98
+ # Specifies which database schemas to dump when calling db:structure:dump.
99
+ # If the value is :schema_search_path (the default), any schemas listed in
100
+ # schema_search_path are dumped. Use :all to dump all schemas regardless
101
+ # of schema_search_path, or a string of comma separated schemas for a
102
+ # custom list.
103
+ mattr_accessor :dump_schemas, instance_writer: false
104
+ self.dump_schemas = :schema_search_path
105
+
106
+ ##
107
+ # :singleton-method:
108
+ # Specify a threshold for the size of query result sets. If the number of
109
+ # records in the set exceeds the threshold, a warning is logged. This can
110
+ # be used to identify queries which load thousands of records and
111
+ # potentially cause memory bloat.
112
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
113
+ self.warn_on_records_fetched_greater_than = nil
114
+
88
115
  mattr_accessor :maintain_test_schema, instance_accessor: false
89
116
 
90
- def self.disable_implicit_join_references=(value)
91
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
92
- Implicit join references were removed with Rails 4.1.
93
- Make sure to remove this configuration because it does nothing.
94
- MSG
95
- end
117
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
96
118
 
97
119
  class_attribute :default_connection_handler, instance_writer: false
98
- class_attribute :find_by_statement_cache
99
120
 
100
121
  def self.connection_handler
101
122
  ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
@@ -114,23 +135,22 @@ module ActiveRecord
114
135
  super
115
136
  end
116
137
 
117
- def initialize_find_by_cache
118
- self.find_by_statement_cache = {}.extend(Mutex_m)
138
+ def initialize_find_by_cache # :nodoc:
139
+ @find_by_statement_cache = { true => {}.extend(Mutex_m), false => {}.extend(Mutex_m) }
119
140
  end
120
141
 
121
- def inherited(child_class)
142
+ def inherited(child_class) # :nodoc:
143
+ # initialize cache at class definition for thread safety
122
144
  child_class.initialize_find_by_cache
123
145
  super
124
146
  end
125
147
 
126
- def find(*ids)
148
+ def find(*ids) # :nodoc:
127
149
  # We don't have cache keys for this stuff yet
128
150
  return super unless ids.length == 1
129
- # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
130
- return super if ids.first.kind_of?(Symbol)
131
151
  return super if block_given? ||
132
152
  primary_key.nil? ||
133
- default_scopes.any? ||
153
+ scope_attributes? ||
134
154
  columns_hash.include?(inheritance_column) ||
135
155
  ids.first.kind_of?(Array)
136
156
 
@@ -139,63 +159,60 @@ module ActiveRecord
139
159
  id = id.id
140
160
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
141
161
  You are passing an instance of ActiveRecord::Base to `find`.
142
- Please pass the id of the object by calling `.id`
162
+ Please pass the id of the object by calling `.id`.
143
163
  MSG
144
164
  end
165
+
145
166
  key = primary_key
146
167
 
147
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
148
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
149
- where(key => params.bind).limit(1)
150
- }
168
+ statement = cached_find_by_statement(key) { |params|
169
+ where(key => params.bind).limit(1)
151
170
  }
152
- record = s.execute([id], self, connection).first
171
+ record = statement.execute([id], self, connection).first
153
172
  unless record
154
- raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
173
+ raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
174
+ name, primary_key, id)
155
175
  end
156
176
  record
157
177
  rescue RangeError
158
- raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
178
+ raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
179
+ name, primary_key)
159
180
  end
160
181
 
161
- def find_by(*args)
162
- return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
163
- return super if default_scopes.any?
182
+ def find_by(*args) # :nodoc:
183
+ return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
164
184
 
165
185
  hash = args.first
166
186
 
167
187
  return super if hash.values.any? { |v|
168
- v.nil? || Array === v || Hash === v
188
+ v.nil? || Array === v || Hash === v || Relation === v
169
189
  }
170
190
 
171
191
  # We can't cache Post.find_by(author: david) ...yet
172
192
  return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
173
193
 
174
- key = hash.keys
194
+ keys = hash.keys
175
195
 
176
- klass = self
177
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
178
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
179
- wheres = key.each_with_object({}) { |param,o|
180
- o[param] = params.bind
181
- }
182
- klass.where(wheres).limit(1)
196
+ statement = cached_find_by_statement(keys) { |params|
197
+ wheres = keys.each_with_object({}) { |param, o|
198
+ o[param] = params.bind
183
199
  }
200
+ where(wheres).limit(1)
184
201
  }
185
202
  begin
186
- s.execute(hash.values, self, connection).first
187
- rescue TypeError => e
188
- raise ActiveRecord::StatementInvalid.new(e.message, e)
203
+ statement.execute(hash.values, self, connection).first
204
+ rescue TypeError
205
+ raise ActiveRecord::StatementInvalid
189
206
  rescue RangeError
190
207
  nil
191
208
  end
192
209
  end
193
210
 
194
- def find_by!(*args)
195
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
211
+ def find_by!(*args) # :nodoc:
212
+ find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
196
213
  end
197
214
 
198
- def initialize_generated_modules
215
+ def initialize_generated_modules # :nodoc:
199
216
  generated_association_methods
200
217
  end
201
218
 
@@ -216,7 +233,7 @@ module ActiveRecord
216
233
  elsif !connected?
217
234
  "#{super} (call '#{super}.connection' to establish a connection)"
218
235
  elsif table_exists?
219
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
236
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
220
237
  "#{super}(#{attr_list})"
221
238
  else
222
239
  "#{super}(Table doesn't exist)"
@@ -234,30 +251,54 @@ module ActiveRecord
234
251
  # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
235
252
  # end
236
253
  def arel_table # :nodoc:
237
- @arel_table ||= Arel::Table.new(table_name, arel_engine)
254
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
238
255
  end
239
256
 
240
257
  # Returns the Arel engine.
241
258
  def arel_engine # :nodoc:
242
259
  @arel_engine ||=
243
- if Base == self || connection_handler.retrieve_connection_pool(self)
260
+ if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
244
261
  self
245
262
  else
246
263
  superclass.arel_engine
247
264
  end
248
265
  end
249
266
 
267
+ def arel_attribute(name, table = arel_table) # :nodoc:
268
+ name = attribute_alias(name) if attribute_alias?(name)
269
+ table[name]
270
+ end
271
+
272
+ def predicate_builder # :nodoc:
273
+ @predicate_builder ||= PredicateBuilder.new(table_metadata)
274
+ end
275
+
276
+ def type_caster # :nodoc:
277
+ TypeCaster::Map.new(self)
278
+ end
279
+
250
280
  private
251
281
 
252
- def relation #:nodoc:
253
- relation = Relation.create(self, arel_table)
282
+ def cached_find_by_statement(key, &block) # :nodoc:
283
+ cache = @find_by_statement_cache[connection.prepared_statements]
284
+ cache[key] || cache.synchronize {
285
+ cache[key] ||= StatementCache.create(connection, &block)
286
+ }
287
+ end
288
+
289
+ def relation # :nodoc:
290
+ relation = Relation.create(self, arel_table, predicate_builder)
254
291
 
255
- if finder_needs_type_condition?
292
+ if finder_needs_type_condition? && !ignore_default_scope?
256
293
  relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
257
294
  else
258
295
  relation
259
296
  end
260
297
  end
298
+
299
+ def table_metadata # :nodoc:
300
+ TableMetadata.new(self, arel_table)
301
+ end
261
302
  end
262
303
 
263
304
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -268,32 +309,35 @@ module ActiveRecord
268
309
  # ==== Example:
269
310
  # # Instantiates a single new object
270
311
  # User.new(first_name: 'Jamie')
271
- def initialize(attributes = nil, options = {})
272
- @attributes = self.class._default_attributes.dup
312
+ def initialize(attributes = nil)
313
+ @attributes = self.class._default_attributes.deep_dup
314
+ self.class.define_attribute_methods
273
315
 
274
316
  init_internals
275
317
  initialize_internals_callback
276
318
 
277
- self.class.define_attribute_methods
278
- # +options+ argument is only needed to make protected_attributes gem easier to hook.
279
- # Remove it when we drop support to this gem.
280
- init_attributes(attributes, options) if attributes
319
+ assign_attributes(attributes) if attributes
281
320
 
282
321
  yield self if block_given?
283
322
  _run_initialize_callbacks
284
323
  end
285
324
 
286
- # Initialize an empty model object from +coder+. +coder+ must contain
287
- # the attributes necessary for initializing an empty model object. For
288
- # example:
325
+ # Initialize an empty model object from +coder+. +coder+ should be
326
+ # the result of previously encoding an Active Record model, using
327
+ # #encode_with.
289
328
  #
290
329
  # class Post < ActiveRecord::Base
291
330
  # end
292
331
  #
332
+ # old_post = Post.new(title: "hello world")
333
+ # coder = {}
334
+ # old_post.encode_with(coder)
335
+ #
293
336
  # post = Post.allocate
294
- # post.init_with('attributes' => { 'title' => 'hello world' })
337
+ # post.init_with(coder)
295
338
  # post.title # => 'hello world'
296
339
  def init_with(coder)
340
+ coder = LegacyYamlAdapter.convert(self.class, coder)
297
341
  @attributes = coder['attributes']
298
342
 
299
343
  init_internals
@@ -336,14 +380,11 @@ module ActiveRecord
336
380
 
337
381
  ##
338
382
  def initialize_dup(other) # :nodoc:
339
- @attributes = @attributes.dup
383
+ @attributes = @attributes.deep_dup
340
384
  @attributes.reset(self.class.primary_key)
341
385
 
342
386
  _run_initialize_callbacks
343
387
 
344
- @aggregation_cache = {}
345
- @association_cache = {}
346
-
347
388
  @new_record = true
348
389
  @destroyed = false
349
390
 
@@ -352,7 +393,7 @@ module ActiveRecord
352
393
 
353
394
  # Populate +coder+ with attributes about this record that should be
354
395
  # serialized. The structure of +coder+ defined in this method is
355
- # guaranteed to match the structure of +coder+ passed to the +init_with+
396
+ # guaranteed to match the structure of +coder+ passed to the #init_with
356
397
  # method.
357
398
  #
358
399
  # Example:
@@ -367,6 +408,7 @@ module ActiveRecord
367
408
  coder['raw_attributes'] = attributes_before_type_cast
368
409
  coder['attributes'] = @attributes
369
410
  coder['new_record'] = new_record?
411
+ coder['active_record_yaml_version'] = 1
370
412
  end
371
413
 
372
414
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -449,9 +491,10 @@ module ActiveRecord
449
491
  "#<#{self.class} #{inspection}>"
450
492
  end
451
493
 
452
- # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
494
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
453
495
  # when pp is required.
454
496
  def pretty_print(pp)
497
+ return super if custom_inspect_method_defined?
455
498
  pp.object_address_group(self) do
456
499
  if defined?(@attributes) && @attributes
457
500
  column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
@@ -477,51 +520,8 @@ module ActiveRecord
477
520
  Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
478
521
  end
479
522
 
480
- def set_transaction_state(state) # :nodoc:
481
- @transaction_state = state
482
- end
483
-
484
- def has_transactional_callbacks? # :nodoc:
485
- !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty?
486
- end
487
-
488
523
  private
489
524
 
490
- # Updates the attributes on this particular ActiveRecord object so that
491
- # if it is associated with a transaction, then the state of the AR object
492
- # will be updated to reflect the current state of the transaction
493
- #
494
- # The @transaction_state variable stores the states of the associated
495
- # transaction. This relies on the fact that a transaction can only be in
496
- # one rollback or commit (otherwise a list of states would be required)
497
- # Each AR object inside of a transaction carries that transaction's
498
- # TransactionState.
499
- #
500
- # This method checks to see if the ActiveRecord object's state reflects
501
- # the TransactionState, and rolls back or commits the ActiveRecord object
502
- # as appropriate.
503
- #
504
- # Since ActiveRecord objects can be inside multiple transactions, this
505
- # method recursively goes through the parent of the TransactionState and
506
- # checks if the ActiveRecord object reflects the state of the object.
507
- def sync_with_transaction_state
508
- update_attributes_from_transaction_state(@transaction_state, 0)
509
- end
510
-
511
- def update_attributes_from_transaction_state(transaction_state, depth)
512
- if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
513
- unless @reflects_state[depth]
514
- restore_transaction_record_state if transaction_state.rolledback?
515
- clear_transaction_record_state
516
- @reflects_state[depth] = true
517
- end
518
-
519
- if transaction_state.parent && !@reflects_state[depth+1]
520
- update_attributes_from_transaction_state(transaction_state.parent, depth+1)
521
- end
522
- end
523
- end
524
-
525
525
  # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
526
526
  # of the array, and then rescues from the possible NoMethodError. If those elements are
527
527
  # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
@@ -535,8 +535,6 @@ module ActiveRecord
535
535
  end
536
536
 
537
537
  def init_internals
538
- @aggregation_cache = {}
539
- @association_cache = {}
540
538
  @readonly = false
541
539
  @destroyed = false
542
540
  @marked_for_destruction = false
@@ -545,22 +543,19 @@ module ActiveRecord
545
543
  @txn = nil
546
544
  @_start_transaction_state = {}
547
545
  @transaction_state = nil
548
- @reflects_state = [false]
549
546
  end
550
547
 
551
548
  def initialize_internals_callback
552
549
  end
553
550
 
554
- # This method is needed to make protected_attributes gem easier to hook.
555
- # Remove it when we drop support to this gem.
556
- def init_attributes(attributes, options)
557
- assign_attributes(attributes)
558
- end
559
-
560
551
  def thaw
561
552
  if frozen?
562
553
  @attributes = @attributes.dup
563
554
  end
564
555
  end
556
+
557
+ def custom_inspect_method_defined?
558
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
559
+ end
565
560
  end
566
561
  end
@@ -37,23 +37,22 @@ module ActiveRecord
37
37
  reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
38
38
  counter_name = reflection.counter_cache_column
39
39
 
40
- stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
41
- arel_table[counter_name] => object.send(counter_association).count(:all)
42
- }, primary_key)
43
- connection.update stmt
40
+ unscoped.where(primary_key => object.id).update_all(
41
+ counter_name => object.send(counter_association).count(:all)
42
+ )
44
43
  end
45
44
  return true
46
45
  end
47
46
 
48
47
  # A generic "counter updater" implementation, intended primarily to be
49
- # used by increment_counter and decrement_counter, but which may also
48
+ # used by #increment_counter and #decrement_counter, but which may also
50
49
  # be useful on its own. It simply does a direct SQL update for the record
51
50
  # with the given ID, altering the given hash of counters by the amount
52
51
  # given by the corresponding value:
53
52
  #
54
53
  # ==== Parameters
55
54
  #
56
- # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
55
+ # * +id+ - The id of the object you wish to update a counter on or an array of ids.
57
56
  # * +counters+ - A Hash containing the names of the fields
58
57
  # to update as keys and the amount to update the field by as values.
59
58
  #
@@ -87,52 +86,42 @@ module ActiveRecord
87
86
  # Increment a numeric field by one, via a direct SQL update.
88
87
  #
89
88
  # This method is used primarily for maintaining counter_cache columns that are
90
- # used to store aggregate values. For example, a DiscussionBoard may cache
89
+ # used to store aggregate values. For example, a +DiscussionBoard+ may cache
91
90
  # posts_count and comments_count to avoid running an SQL query to calculate the
92
91
  # number of posts and comments there are, each time it is displayed.
93
92
  #
94
93
  # ==== Parameters
95
94
  #
96
95
  # * +counter_name+ - The name of the field that should be incremented.
97
- # * +id+ - The id of the object that should be incremented or an Array of ids.
96
+ # * +id+ - The id of the object that should be incremented or an array of ids.
98
97
  #
99
98
  # ==== Examples
100
99
  #
101
- # # Increment the post_count column for the record with an id of 5
102
- # DiscussionBoard.increment_counter(:post_count, 5)
100
+ # # Increment the posts_count column for the record with an id of 5
101
+ # DiscussionBoard.increment_counter(:posts_count, 5)
103
102
  def increment_counter(counter_name, id)
104
103
  update_counters(id, counter_name => 1)
105
104
  end
106
105
 
107
106
  # Decrement a numeric field by one, via a direct SQL update.
108
107
  #
109
- # This works the same as increment_counter but reduces the column value by
108
+ # This works the same as #increment_counter but reduces the column value by
110
109
  # 1 instead of increasing it.
111
110
  #
112
111
  # ==== Parameters
113
112
  #
114
113
  # * +counter_name+ - The name of the field that should be decremented.
115
- # * +id+ - The id of the object that should be decremented or an Array of ids.
114
+ # * +id+ - The id of the object that should be decremented or an array of ids.
116
115
  #
117
116
  # ==== Examples
118
117
  #
119
- # # Decrement the post_count column for the record with an id of 5
120
- # DiscussionBoard.decrement_counter(:post_count, 5)
118
+ # # Decrement the posts_count column for the record with an id of 5
119
+ # DiscussionBoard.decrement_counter(:posts_count, 5)
121
120
  def decrement_counter(counter_name, id)
122
121
  update_counters(id, counter_name => -1)
123
122
  end
124
123
  end
125
124
 
126
- protected
127
-
128
- def actually_destroyed?
129
- @_actually_destroyed
130
- end
131
-
132
- def clear_destroy_state
133
- @_actually_destroyed = nil
134
- end
135
-
136
125
  private
137
126
 
138
127
  def _create_record(*)
@@ -167,7 +156,7 @@ module ActiveRecord
167
156
 
168
157
  def each_counter_cached_associations
169
158
  _reflections.each do |name, reflection|
170
- yield association(name) if reflection.belongs_to? && reflection.counter_cache_column
159
+ yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
171
160
  end
172
161
  end
173
162
 
@@ -1,10 +1,5 @@
1
1
  module ActiveRecord
2
2
  module DynamicMatchers #:nodoc:
3
- # This code in this file seems to have a lot of indirection, but the indirection
4
- # is there to provide extension points for the activerecord-deprecated_finders
5
- # gem. When we stop supporting activerecord-deprecated_finders (from Rails 5),
6
- # then we can remove the indirection.
7
-
8
3
  def respond_to?(name, include_private = false)
9
4
  if self == Base
10
5
  super
@@ -72,26 +67,14 @@ module ActiveRecord
72
67
  CODE
73
68
  end
74
69
 
75
- def body
76
- raise NotImplementedError
77
- end
78
- end
70
+ private
79
71
 
80
- module Finder
81
- # Extended in activerecord-deprecated_finders
82
72
  def body
83
- result
84
- end
85
-
86
- # Extended in activerecord-deprecated_finders
87
- def result
88
73
  "#{finder}(#{attributes_hash})"
89
74
  end
90
75
 
91
76
  # The parameters in the signature may have reserved Ruby words, in order
92
77
  # to prevent errors, we start each param name with `_`.
93
- #
94
- # Extended in activerecord-deprecated_finders
95
78
  def signature
96
79
  attribute_names.map { |name| "_#{name}" }.join(', ')
97
80
  end
@@ -109,7 +92,6 @@ module ActiveRecord
109
92
 
110
93
  class FindBy < Method
111
94
  Method.matchers << self
112
- include Finder
113
95
 
114
96
  def self.prefix
115
97
  "find_by"
@@ -122,7 +104,6 @@ module ActiveRecord
122
104
 
123
105
  class FindByBang < Method
124
106
  Method.matchers << self
125
- include Finder
126
107
 
127
108
  def self.prefix
128
109
  "find_by"