activerecord 3.2.22.5 → 4.2.11.3

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