activerecord 3.2.19 → 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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,561 @@
1
+ require 'thread'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+ require 'active_support/core_ext/object/duplicable'
4
+ require 'active_support/core_ext/string/filters'
5
+
6
+ module ActiveRecord
7
+ module Core
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ ##
12
+ # :singleton-method:
13
+ #
14
+ # Accepts a logger conforming to the interface of Log4r which is then
15
+ # passed on to any new database connections made and which can be
16
+ # retrieved on both a class and instance level by calling +logger+.
17
+ mattr_accessor :logger, instance_writer: false
18
+
19
+ ##
20
+ # Contains the database configuration - as is typically stored in config/database.yml -
21
+ # as a Hash.
22
+ #
23
+ # For example, the following database.yml...
24
+ #
25
+ # development:
26
+ # adapter: sqlite3
27
+ # database: db/development.sqlite3
28
+ #
29
+ # production:
30
+ # adapter: sqlite3
31
+ # database: db/production.sqlite3
32
+ #
33
+ # ...would result in ActiveRecord::Base.configurations to look like this:
34
+ #
35
+ # {
36
+ # 'development' => {
37
+ # 'adapter' => 'sqlite3',
38
+ # 'database' => 'db/development.sqlite3'
39
+ # },
40
+ # 'production' => {
41
+ # 'adapter' => 'sqlite3',
42
+ # 'database' => 'db/production.sqlite3'
43
+ # }
44
+ # }
45
+ def self.configurations=(config)
46
+ @@configurations = ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig.new(config).resolve
47
+ end
48
+ self.configurations = {}
49
+
50
+ # Returns fully resolved configurations hash
51
+ def self.configurations
52
+ @@configurations
53
+ end
54
+
55
+ ##
56
+ # :singleton-method:
57
+ # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
58
+ # dates and times from the database. This is set to :utc by default.
59
+ mattr_accessor :default_timezone, instance_writer: false
60
+ self.default_timezone = :utc
61
+
62
+ ##
63
+ # :singleton-method:
64
+ # Specifies the format to use when dumping the database schema with Rails'
65
+ # Rakefile. If :sql, the schema is dumped as (potentially database-
66
+ # specific) SQL statements. If :ruby, the schema is dumped as an
67
+ # ActiveRecord::Schema file which can be loaded into any database that
68
+ # supports migrations. Use :ruby if you want to have different database
69
+ # adapters for, e.g., your development and test environments.
70
+ mattr_accessor :schema_format, instance_writer: false
71
+ self.schema_format = :ruby
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
+
81
+ ##
82
+ # :singleton-method:
83
+ # Specify whether or not to use timestamps for migration versions
84
+ mattr_accessor :timestamped_migrations, instance_writer: false
85
+ self.timestamped_migrations = true
86
+
87
+ ##
88
+ # :singleton-method:
89
+ # Specify whether schema dump should happen at the end of the
90
+ # db:migrate rake task. This is true by default, which is useful for the
91
+ # development environment. This should ideally be false in the production
92
+ # environment where dumping schema is rarely needed.
93
+ mattr_accessor :dump_schema_after_migration, instance_writer: false
94
+ self.dump_schema_after_migration = true
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
+
115
+ mattr_accessor :maintain_test_schema, instance_accessor: false
116
+
117
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
118
+
119
+ class_attribute :default_connection_handler, instance_writer: false
120
+
121
+ def self.connection_handler
122
+ ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
123
+ end
124
+
125
+ def self.connection_handler=(handler)
126
+ ActiveRecord::RuntimeRegistry.connection_handler = handler
127
+ end
128
+
129
+ self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
130
+ end
131
+
132
+ module ClassMethods
133
+ def allocate
134
+ define_attribute_methods
135
+ super
136
+ end
137
+
138
+ def initialize_find_by_cache # :nodoc:
139
+ @find_by_statement_cache = { true => {}.extend(Mutex_m), false => {}.extend(Mutex_m) }
140
+ end
141
+
142
+ def inherited(child_class) # :nodoc:
143
+ # initialize cache at class definition for thread safety
144
+ child_class.initialize_find_by_cache
145
+ super
146
+ end
147
+
148
+ def find(*ids) # :nodoc:
149
+ # We don't have cache keys for this stuff yet
150
+ return super unless ids.length == 1
151
+ return super if block_given? ||
152
+ primary_key.nil? ||
153
+ scope_attributes? ||
154
+ columns_hash.include?(inheritance_column) ||
155
+ ids.first.kind_of?(Array)
156
+
157
+ id = ids.first
158
+ if ActiveRecord::Base === id
159
+ id = id.id
160
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
161
+ You are passing an instance of ActiveRecord::Base to `find`.
162
+ Please pass the id of the object by calling `.id`.
163
+ MSG
164
+ end
165
+
166
+ key = primary_key
167
+
168
+ statement = cached_find_by_statement(key) { |params|
169
+ where(key => params.bind).limit(1)
170
+ }
171
+ record = statement.execute([id], self, connection).first
172
+ unless record
173
+ raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
174
+ name, primary_key, id)
175
+ end
176
+ record
177
+ rescue RangeError
178
+ raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
179
+ name, primary_key)
180
+ end
181
+
182
+ def find_by(*args) # :nodoc:
183
+ return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
184
+
185
+ hash = args.first
186
+
187
+ return super if hash.values.any? { |v|
188
+ v.nil? || Array === v || Hash === v || Relation === v
189
+ }
190
+
191
+ # We can't cache Post.find_by(author: david) ...yet
192
+ return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
193
+
194
+ keys = hash.keys
195
+
196
+ statement = cached_find_by_statement(keys) { |params|
197
+ wheres = keys.each_with_object({}) { |param, o|
198
+ o[param] = params.bind
199
+ }
200
+ where(wheres).limit(1)
201
+ }
202
+ begin
203
+ statement.execute(hash.values, self, connection).first
204
+ rescue TypeError
205
+ raise ActiveRecord::StatementInvalid
206
+ rescue RangeError
207
+ nil
208
+ end
209
+ end
210
+
211
+ def find_by!(*args) # :nodoc:
212
+ find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
213
+ end
214
+
215
+ def initialize_generated_modules # :nodoc:
216
+ generated_association_methods
217
+ end
218
+
219
+ def generated_association_methods
220
+ @generated_association_methods ||= begin
221
+ mod = const_set(:GeneratedAssociationMethods, Module.new)
222
+ include mod
223
+ mod
224
+ end
225
+ end
226
+
227
+ # Returns a string like 'Post(id:integer, title:string, body:text)'
228
+ def inspect
229
+ if self == Base
230
+ super
231
+ elsif abstract_class?
232
+ "#{super}(abstract)"
233
+ elsif !connected?
234
+ "#{super} (call '#{super}.connection' to establish a connection)"
235
+ elsif table_exists?
236
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
237
+ "#{super}(#{attr_list})"
238
+ else
239
+ "#{super}(Table doesn't exist)"
240
+ end
241
+ end
242
+
243
+ # Overwrite the default class equality method to provide support for association proxies.
244
+ def ===(object)
245
+ object.is_a?(self)
246
+ end
247
+
248
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
249
+ #
250
+ # class Post < ActiveRecord::Base
251
+ # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
252
+ # end
253
+ def arel_table # :nodoc:
254
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
255
+ end
256
+
257
+ # Returns the Arel engine.
258
+ def arel_engine # :nodoc:
259
+ @arel_engine ||=
260
+ if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
261
+ self
262
+ else
263
+ superclass.arel_engine
264
+ end
265
+ end
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
+
280
+ private
281
+
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)
291
+
292
+ if finder_needs_type_condition? && !ignore_default_scope?
293
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
294
+ else
295
+ relation
296
+ end
297
+ end
298
+
299
+ def table_metadata # :nodoc:
300
+ TableMetadata.new(self, arel_table)
301
+ end
302
+ end
303
+
304
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
305
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
306
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
307
+ # hence you can't have attributes that aren't part of the table columns.
308
+ #
309
+ # ==== Example:
310
+ # # Instantiates a single new object
311
+ # User.new(first_name: 'Jamie')
312
+ def initialize(attributes = nil)
313
+ @attributes = self.class._default_attributes.deep_dup
314
+ self.class.define_attribute_methods
315
+
316
+ init_internals
317
+ initialize_internals_callback
318
+
319
+ assign_attributes(attributes) if attributes
320
+
321
+ yield self if block_given?
322
+ _run_initialize_callbacks
323
+ end
324
+
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.
328
+ #
329
+ # class Post < ActiveRecord::Base
330
+ # end
331
+ #
332
+ # old_post = Post.new(title: "hello world")
333
+ # coder = {}
334
+ # old_post.encode_with(coder)
335
+ #
336
+ # post = Post.allocate
337
+ # post.init_with(coder)
338
+ # post.title # => 'hello world'
339
+ def init_with(coder)
340
+ coder = LegacyYamlAdapter.convert(self.class, coder)
341
+ @attributes = coder['attributes']
342
+
343
+ init_internals
344
+
345
+ @new_record = coder['new_record']
346
+
347
+ self.class.define_attribute_methods
348
+
349
+ _run_find_callbacks
350
+ _run_initialize_callbacks
351
+
352
+ self
353
+ end
354
+
355
+ ##
356
+ # :method: clone
357
+ # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
358
+ # That means that modifying attributes of the clone will modify the original, since they will both point to the
359
+ # same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
360
+ #
361
+ # user = User.first
362
+ # new_user = user.clone
363
+ # user.name # => "Bob"
364
+ # new_user.name = "Joe"
365
+ # user.name # => "Joe"
366
+ #
367
+ # user.object_id == new_user.object_id # => false
368
+ # user.name.object_id == new_user.name.object_id # => true
369
+ #
370
+ # user.name.object_id == user.dup.name.object_id # => false
371
+
372
+ ##
373
+ # :method: dup
374
+ # Duped objects have no id assigned and are treated as new records. Note
375
+ # that this is a "shallow" copy as it copies the object's attributes
376
+ # only, not its associations. The extent of a "deep" copy is application
377
+ # specific and is therefore left to the application to implement according
378
+ # to its need.
379
+ # The dup method does not preserve the timestamps (created|updated)_(at|on).
380
+
381
+ ##
382
+ def initialize_dup(other) # :nodoc:
383
+ @attributes = @attributes.deep_dup
384
+ @attributes.reset(self.class.primary_key)
385
+
386
+ _run_initialize_callbacks
387
+
388
+ @new_record = true
389
+ @destroyed = false
390
+
391
+ super
392
+ end
393
+
394
+ # Populate +coder+ with attributes about this record that should be
395
+ # serialized. The structure of +coder+ defined in this method is
396
+ # guaranteed to match the structure of +coder+ passed to the #init_with
397
+ # method.
398
+ #
399
+ # Example:
400
+ #
401
+ # class Post < ActiveRecord::Base
402
+ # end
403
+ # coder = {}
404
+ # Post.new.encode_with(coder)
405
+ # coder # => {"attributes" => {"id" => nil, ... }}
406
+ def encode_with(coder)
407
+ # FIXME: Remove this when we better serialize attributes
408
+ coder['raw_attributes'] = attributes_before_type_cast
409
+ coder['attributes'] = @attributes
410
+ coder['new_record'] = new_record?
411
+ coder['active_record_yaml_version'] = 1
412
+ end
413
+
414
+ # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
415
+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
416
+ #
417
+ # Note that new records are different from any other record by definition, unless the
418
+ # other record is the receiver itself. Besides, if you fetch existing records with
419
+ # +select+ and leave the ID out, you're on your own, this predicate will return false.
420
+ #
421
+ # Note also that destroying a record preserves its ID in the model instance, so deleted
422
+ # models are still comparable.
423
+ def ==(comparison_object)
424
+ super ||
425
+ comparison_object.instance_of?(self.class) &&
426
+ !id.nil? &&
427
+ comparison_object.id == id
428
+ end
429
+ alias :eql? :==
430
+
431
+ # Delegates to id in order to allow two records of the same type and id to work with something like:
432
+ # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
433
+ def hash
434
+ if id
435
+ id.hash
436
+ else
437
+ super
438
+ end
439
+ end
440
+
441
+ # Clone and freeze the attributes hash such that associations are still
442
+ # accessible, even on destroyed records, but cloned models will not be
443
+ # frozen.
444
+ def freeze
445
+ @attributes = @attributes.clone.freeze
446
+ self
447
+ end
448
+
449
+ # Returns +true+ if the attributes hash has been frozen.
450
+ def frozen?
451
+ @attributes.frozen?
452
+ end
453
+
454
+ # Allows sort on objects
455
+ def <=>(other_object)
456
+ if other_object.is_a?(self.class)
457
+ self.to_key <=> other_object.to_key
458
+ else
459
+ super
460
+ end
461
+ end
462
+
463
+ # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
464
+ # attributes will be marked as read only since they cannot be saved.
465
+ def readonly?
466
+ @readonly
467
+ end
468
+
469
+ # Marks this record as read only.
470
+ def readonly!
471
+ @readonly = true
472
+ end
473
+
474
+ def connection_handler
475
+ self.class.connection_handler
476
+ end
477
+
478
+ # Returns the contents of the record as a nicely formatted string.
479
+ def inspect
480
+ # We check defined?(@attributes) not to issue warnings if the object is
481
+ # allocated but not initialized.
482
+ inspection = if defined?(@attributes) && @attributes
483
+ self.class.column_names.collect { |name|
484
+ if has_attribute?(name)
485
+ "#{name}: #{attribute_for_inspect(name)}"
486
+ end
487
+ }.compact.join(", ")
488
+ else
489
+ "not initialized"
490
+ end
491
+ "#<#{self.class} #{inspection}>"
492
+ end
493
+
494
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
495
+ # when pp is required.
496
+ def pretty_print(pp)
497
+ return super if custom_inspect_method_defined?
498
+ pp.object_address_group(self) do
499
+ if defined?(@attributes) && @attributes
500
+ column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
501
+ pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
502
+ column_value = read_attribute(column_name)
503
+ pp.breakable ' '
504
+ pp.group(1) do
505
+ pp.text column_name
506
+ pp.text ':'
507
+ pp.breakable
508
+ pp.pp column_value
509
+ end
510
+ end
511
+ else
512
+ pp.breakable ' '
513
+ pp.text 'not initialized'
514
+ end
515
+ end
516
+ end
517
+
518
+ # Returns a hash of the given methods with their names as keys and returned values as values.
519
+ def slice(*methods)
520
+ Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
521
+ end
522
+
523
+ private
524
+
525
+ # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
526
+ # of the array, and then rescues from the possible NoMethodError. If those elements are
527
+ # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
528
+ # which significantly impacts upon performance.
529
+ #
530
+ # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
531
+ #
532
+ # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
533
+ def to_ary # :nodoc:
534
+ nil
535
+ end
536
+
537
+ def init_internals
538
+ @readonly = false
539
+ @destroyed = false
540
+ @marked_for_destruction = false
541
+ @destroyed_by_association = nil
542
+ @new_record = true
543
+ @txn = nil
544
+ @_start_transaction_state = {}
545
+ @transaction_state = nil
546
+ end
547
+
548
+ def initialize_internals_callback
549
+ end
550
+
551
+ def thaw
552
+ if frozen?
553
+ @attributes = @attributes.dup
554
+ end
555
+ end
556
+
557
+ def custom_inspect_method_defined?
558
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
559
+ end
560
+ end
561
+ end