activerecord 3.2.22.4 → 4.0.13

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2799 -617
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +23 -32
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +40 -34
  7. data/lib/active_record/association_relation.rb +22 -0
  8. data/lib/active_record/associations/alias_tracker.rb +4 -2
  9. data/lib/active_record/associations/association.rb +60 -46
  10. data/lib/active_record/associations/association_scope.rb +46 -40
  11. data/lib/active_record/associations/belongs_to_association.rb +17 -4
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +73 -56
  15. data/lib/active_record/associations/builder/collection_association.rb +54 -40
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -64
  18. data/lib/active_record/associations/builder/has_one.rb +13 -50
  19. data/lib/active_record/associations/builder/singular_association.rb +13 -13
  20. data/lib/active_record/associations/collection_association.rb +130 -96
  21. data/lib/active_record/associations/collection_proxy.rb +916 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
  23. data/lib/active_record/associations/has_many_association.rb +35 -8
  24. data/lib/active_record/associations/has_many_through_association.rb +37 -17
  25. data/lib/active_record/associations/has_one_association.rb +42 -19
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
  28. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  29. data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
  30. data/lib/active_record/associations/join_dependency.rb +30 -9
  31. data/lib/active_record/associations/join_helper.rb +1 -11
  32. data/lib/active_record/associations/preloader/association.rb +29 -33
  33. data/lib/active_record/associations/preloader/collection_association.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  36. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +13 -17
  38. data/lib/active_record/associations/preloader.rb +20 -43
  39. data/lib/active_record/associations/singular_association.rb +11 -11
  40. data/lib/active_record/associations/through_association.rb +3 -3
  41. data/lib/active_record/associations.rb +223 -282
  42. data/lib/active_record/attribute_assignment.rb +134 -154
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  44. data/lib/active_record/attribute_methods/dirty.rb +36 -29
  45. data/lib/active_record/attribute_methods/primary_key.rb +45 -31
  46. data/lib/active_record/attribute_methods/query.rb +5 -4
  47. data/lib/active_record/attribute_methods/read.rb +67 -90
  48. data/lib/active_record/attribute_methods/serialization.rb +133 -70
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
  50. data/lib/active_record/attribute_methods/write.rb +34 -39
  51. data/lib/active_record/attribute_methods.rb +268 -108
  52. data/lib/active_record/autosave_association.rb +80 -73
  53. data/lib/active_record/base.rb +54 -451
  54. data/lib/active_record/callbacks.rb +60 -22
  55. data/lib/active_record/coders/yaml_column.rb +18 -21
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
  67. data/lib/active_record/connection_adapters/column.rb +67 -36
  68. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
  70. data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
  71. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
  72. data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
  79. data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
  80. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
  81. data/lib/active_record/connection_handling.rb +98 -0
  82. data/lib/active_record/core.rb +472 -0
  83. data/lib/active_record/counter_cache.rb +107 -108
  84. data/lib/active_record/dynamic_matchers.rb +115 -63
  85. data/lib/active_record/errors.rb +36 -18
  86. data/lib/active_record/explain.rb +15 -63
  87. data/lib/active_record/explain_registry.rb +30 -0
  88. data/lib/active_record/explain_subscriber.rb +8 -4
  89. data/lib/active_record/fixture_set/file.rb +55 -0
  90. data/lib/active_record/fixtures.rb +159 -155
  91. data/lib/active_record/inheritance.rb +93 -59
  92. data/lib/active_record/integration.rb +8 -8
  93. data/lib/active_record/locale/en.yml +8 -1
  94. data/lib/active_record/locking/optimistic.rb +39 -43
  95. data/lib/active_record/locking/pessimistic.rb +4 -4
  96. data/lib/active_record/log_subscriber.rb +19 -9
  97. data/lib/active_record/migration/command_recorder.rb +102 -33
  98. data/lib/active_record/migration/join_table.rb +15 -0
  99. data/lib/active_record/migration.rb +411 -173
  100. data/lib/active_record/model_schema.rb +81 -94
  101. data/lib/active_record/nested_attributes.rb +173 -131
  102. data/lib/active_record/null_relation.rb +67 -0
  103. data/lib/active_record/persistence.rb +254 -106
  104. data/lib/active_record/query_cache.rb +18 -36
  105. data/lib/active_record/querying.rb +19 -15
  106. data/lib/active_record/railtie.rb +113 -38
  107. data/lib/active_record/railties/console_sandbox.rb +3 -4
  108. data/lib/active_record/railties/controller_runtime.rb +4 -3
  109. data/lib/active_record/railties/databases.rake +115 -368
  110. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  111. data/lib/active_record/readonly_attributes.rb +7 -3
  112. data/lib/active_record/reflection.rb +110 -61
  113. data/lib/active_record/relation/batches.rb +29 -29
  114. data/lib/active_record/relation/calculations.rb +155 -125
  115. data/lib/active_record/relation/delegation.rb +94 -18
  116. data/lib/active_record/relation/finder_methods.rb +151 -203
  117. data/lib/active_record/relation/merger.rb +188 -0
  118. data/lib/active_record/relation/predicate_builder.rb +85 -42
  119. data/lib/active_record/relation/query_methods.rb +793 -146
  120. data/lib/active_record/relation/spawn_methods.rb +43 -150
  121. data/lib/active_record/relation.rb +293 -173
  122. data/lib/active_record/result.rb +48 -7
  123. data/lib/active_record/runtime_registry.rb +17 -0
  124. data/lib/active_record/sanitization.rb +41 -54
  125. data/lib/active_record/schema.rb +19 -12
  126. data/lib/active_record/schema_dumper.rb +41 -41
  127. data/lib/active_record/schema_migration.rb +46 -0
  128. data/lib/active_record/scoping/default.rb +56 -52
  129. data/lib/active_record/scoping/named.rb +78 -103
  130. data/lib/active_record/scoping.rb +54 -124
  131. data/lib/active_record/serialization.rb +6 -2
  132. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  133. data/lib/active_record/statement_cache.rb +26 -0
  134. data/lib/active_record/store.rb +131 -15
  135. data/lib/active_record/tasks/database_tasks.rb +204 -0
  136. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
  138. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  140. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  141. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  142. data/lib/active_record/test_case.rb +67 -38
  143. data/lib/active_record/timestamp.rb +16 -11
  144. data/lib/active_record/transactions.rb +73 -51
  145. data/lib/active_record/validations/associated.rb +19 -13
  146. data/lib/active_record/validations/presence.rb +65 -0
  147. data/lib/active_record/validations/uniqueness.rb +110 -57
  148. data/lib/active_record/validations.rb +18 -17
  149. data/lib/active_record/version.rb +7 -6
  150. data/lib/active_record.rb +63 -45
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
  152. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  154. data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
  155. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  156. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  157. data/lib/rails/generators/active_record.rb +3 -5
  158. metadata +43 -29
  159. data/examples/associations.png +0 -0
  160. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  161. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  162. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  163. data/lib/active_record/dynamic_finder_match.rb +0 -68
  164. data/lib/active_record/dynamic_scope_match.rb +0 -23
  165. data/lib/active_record/fixtures/file.rb +0 -65
  166. data/lib/active_record/identity_map.rb +0 -162
  167. data/lib/active_record/observer.rb +0 -121
  168. data/lib/active_record/session_store.rb +0 -360
  169. data/lib/rails/generators/active_record/migration.rb +0 -15
  170. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  171. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  172. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  173. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,98 @@
1
+ module ActiveRecord
2
+ module ConnectionHandling
3
+ # Establishes the connection to the database. Accepts a hash as input where
4
+ # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
5
+ # example for regular databases (MySQL, Postgresql, etc):
6
+ #
7
+ # ActiveRecord::Base.establish_connection(
8
+ # adapter: "mysql",
9
+ # host: "localhost",
10
+ # username: "myuser",
11
+ # password: "mypass",
12
+ # database: "somedatabase"
13
+ # )
14
+ #
15
+ # Example for SQLite database:
16
+ #
17
+ # ActiveRecord::Base.establish_connection(
18
+ # adapter: "sqlite3",
19
+ # database: "path/to/dbfile"
20
+ # )
21
+ #
22
+ # Also accepts keys as strings (for parsing from YAML for example):
23
+ #
24
+ # ActiveRecord::Base.establish_connection(
25
+ # "adapter" => "sqlite3",
26
+ # "database" => "path/to/dbfile"
27
+ # )
28
+ #
29
+ # Or a URL:
30
+ #
31
+ # ActiveRecord::Base.establish_connection(
32
+ # "postgres://myuser:mypass@localhost/somedatabase"
33
+ # )
34
+ #
35
+ # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
36
+ # may be returned on an error.
37
+ def establish_connection(spec = ENV["DATABASE_URL"])
38
+ resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new spec, configurations
39
+ spec = resolver.spec
40
+
41
+ unless respond_to?(spec.adapter_method)
42
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
43
+ end
44
+
45
+ remove_connection
46
+ connection_handler.establish_connection self, spec
47
+ end
48
+
49
+ # Returns the connection currently associated with the class. This can
50
+ # also be used to "borrow" the connection to do database work unrelated
51
+ # to any of the specific Active Records.
52
+ def connection
53
+ retrieve_connection
54
+ end
55
+
56
+ def connection_id
57
+ ActiveRecord::RuntimeRegistry.connection_id
58
+ end
59
+
60
+ def connection_id=(connection_id)
61
+ ActiveRecord::RuntimeRegistry.connection_id = connection_id
62
+ end
63
+
64
+ # Returns the configuration of the associated connection as a hash:
65
+ #
66
+ # ActiveRecord::Base.connection_config
67
+ # # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
68
+ #
69
+ # Please use only for reading.
70
+ def connection_config
71
+ connection_pool.spec.config
72
+ end
73
+
74
+ def connection_pool
75
+ connection_handler.retrieve_connection_pool(self) or raise ConnectionNotEstablished
76
+ end
77
+
78
+ def retrieve_connection
79
+ connection_handler.retrieve_connection(self)
80
+ end
81
+
82
+ # Returns +true+ if Active Record is connected.
83
+ def connected?
84
+ connection_handler.connected?(self)
85
+ end
86
+
87
+ def remove_connection(klass = self)
88
+ connection_handler.remove_connection(klass)
89
+ end
90
+
91
+ def clear_cache! # :nodoc:
92
+ connection.schema_cache.clear!
93
+ end
94
+
95
+ delegate :clear_active_connections!, :clear_reloadable_connections!,
96
+ :clear_all_connections!, :to => :connection_handler
97
+ end
98
+ end
@@ -0,0 +1,472 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/object/duplicable'
3
+ require 'thread'
4
+
5
+ module ActiveRecord
6
+ module Core
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ ##
11
+ # :singleton-method:
12
+ #
13
+ # Accepts a logger conforming to the interface of Log4r which is then
14
+ # passed on to any new database connections made and which can be
15
+ # retrieved on both a class and instance level by calling +logger+.
16
+ mattr_accessor :logger, instance_writer: false
17
+
18
+ ##
19
+ # :singleton-method:
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
+ mattr_accessor :configurations, instance_writer: false
46
+ self.configurations = {}
47
+
48
+ ##
49
+ # :singleton-method:
50
+ # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
51
+ # dates and times from the database. This is set to :utc by default.
52
+ mattr_accessor :default_timezone, instance_writer: false
53
+ self.default_timezone = :utc
54
+
55
+ ##
56
+ # :singleton-method:
57
+ # Specifies the format to use when dumping the database schema with Rails'
58
+ # Rakefile. If :sql, the schema is dumped as (potentially database-
59
+ # specific) SQL statements. If :ruby, the schema is dumped as an
60
+ # ActiveRecord::Schema file which can be loaded into any database that
61
+ # supports migrations. Use :ruby if you want to have different database
62
+ # adapters for, e.g., your development and test environments.
63
+ mattr_accessor :schema_format, instance_writer: false
64
+ self.schema_format = :ruby
65
+
66
+ ##
67
+ # :singleton-method:
68
+ # Specify whether or not to use timestamps for migration versions
69
+ mattr_accessor :timestamped_migrations, instance_writer: false
70
+ self.timestamped_migrations = true
71
+
72
+ ##
73
+ # :singleton-method:
74
+ # Disable implicit join references. This feature was deprecated with Rails 4.
75
+ # If you don't make use of implicit references but still see deprecation warnings
76
+ # you can disable the feature entirely. This will be the default with Rails 4.1.
77
+ mattr_accessor :disable_implicit_join_references, instance_writer: false
78
+ self.disable_implicit_join_references = false
79
+
80
+ class_attribute :default_connection_handler, instance_writer: false
81
+
82
+ def self.connection_handler
83
+ ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
84
+ end
85
+
86
+ def self.connection_handler=(handler)
87
+ ActiveRecord::RuntimeRegistry.connection_handler = handler
88
+ end
89
+
90
+ self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
91
+ end
92
+
93
+ module ClassMethods
94
+ def initialize_generated_modules
95
+ super
96
+
97
+ generated_feature_methods
98
+ end
99
+
100
+ def generated_feature_methods
101
+ @generated_feature_methods ||= begin
102
+ mod = const_set(:GeneratedFeatureMethods, Module.new)
103
+ include mod
104
+ mod
105
+ end
106
+ end
107
+
108
+ # Returns a string like 'Post(id:integer, title:string, body:text)'
109
+ def inspect
110
+ if self == Base
111
+ super
112
+ elsif abstract_class?
113
+ "#{super}(abstract)"
114
+ elsif !connected?
115
+ "#{super} (call '#{super}.connection' to establish a connection)"
116
+ elsif table_exists?
117
+ attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
118
+ "#{super}(#{attr_list})"
119
+ else
120
+ "#{super}(Table doesn't exist)"
121
+ end
122
+ end
123
+
124
+ # Overwrite the default class equality method to provide support for association proxies.
125
+ def ===(object)
126
+ object.is_a?(self)
127
+ end
128
+
129
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
130
+ #
131
+ # class Post < ActiveRecord::Base
132
+ # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
133
+ # end
134
+ def arel_table
135
+ @arel_table ||= Arel::Table.new(table_name, arel_engine)
136
+ end
137
+
138
+ # Returns the Arel engine.
139
+ def arel_engine
140
+ @arel_engine ||= begin
141
+ if Base == self || connection_handler.retrieve_connection_pool(self)
142
+ self
143
+ else
144
+ superclass.arel_engine
145
+ end
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def relation #:nodoc:
152
+ relation = Relation.new(self, arel_table)
153
+
154
+ if finder_needs_type_condition?
155
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
156
+ else
157
+ relation
158
+ end
159
+ end
160
+ end
161
+
162
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
163
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
164
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
165
+ # hence you can't have attributes that aren't part of the table columns.
166
+ #
167
+ # ==== Example:
168
+ # # Instantiates a single new object
169
+ # User.new(first_name: 'Jamie')
170
+ def initialize(attributes = nil, options = {})
171
+ defaults = self.class.column_defaults.dup
172
+ defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
173
+
174
+ @attributes = self.class.initialize_attributes(defaults)
175
+ @column_types_override = nil
176
+ @column_types = self.class.column_types
177
+
178
+ init_internals
179
+ init_changed_attributes
180
+ ensure_proper_type
181
+ populate_with_current_scope_attributes
182
+
183
+ # +options+ argument is only needed to make protected_attributes gem easier to hook.
184
+ # Remove it when we drop support to this gem.
185
+ init_attributes(attributes, options) if attributes
186
+
187
+ yield self if block_given?
188
+ run_callbacks :initialize unless _initialize_callbacks.empty?
189
+ end
190
+
191
+ # Initialize an empty model object from +coder+. +coder+ must contain
192
+ # the attributes necessary for initializing an empty model object. For
193
+ # example:
194
+ #
195
+ # class Post < ActiveRecord::Base
196
+ # end
197
+ #
198
+ # post = Post.allocate
199
+ # post.init_with('attributes' => { 'title' => 'hello world' })
200
+ # post.title # => 'hello world'
201
+ def init_with(coder)
202
+ @attributes = self.class.initialize_attributes(coder['attributes'])
203
+ @column_types_override = coder['column_types']
204
+ @column_types = self.class.column_types
205
+
206
+ init_internals
207
+
208
+ @new_record = false
209
+
210
+ run_callbacks :find
211
+ run_callbacks :initialize
212
+
213
+ self
214
+ end
215
+
216
+ ##
217
+ # :method: clone
218
+ # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
219
+ # That means that modifying attributes of the clone will modify the original, since they will both point to the
220
+ # same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
221
+ #
222
+ # user = User.first
223
+ # new_user = user.clone
224
+ # user.name # => "Bob"
225
+ # new_user.name = "Joe"
226
+ # user.name # => "Joe"
227
+ #
228
+ # user.object_id == new_user.object_id # => false
229
+ # user.name.object_id == new_user.name.object_id # => true
230
+ #
231
+ # user.name.object_id == user.dup.name.object_id # => false
232
+
233
+ ##
234
+ # :method: dup
235
+ # Duped objects have no id assigned and are treated as new records. Note
236
+ # that this is a "shallow" copy as it copies the object's attributes
237
+ # only, not its associations. The extent of a "deep" copy is application
238
+ # specific and is therefore left to the application to implement according
239
+ # to its need.
240
+ # The dup method does not preserve the timestamps (created|updated)_(at|on).
241
+
242
+ ##
243
+ def initialize_dup(other) # :nodoc:
244
+ cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
245
+ self.class.initialize_attributes(cloned_attributes, :serialized => false)
246
+
247
+ @attributes = cloned_attributes
248
+ @attributes[self.class.primary_key] = nil
249
+
250
+ run_callbacks(:initialize) unless _initialize_callbacks.empty?
251
+
252
+ @changed_attributes = {}
253
+ init_changed_attributes
254
+
255
+ @aggregation_cache = {}
256
+ @association_cache = {}
257
+ @attributes_cache = {}
258
+
259
+ @new_record = true
260
+ @destroyed = false
261
+
262
+ ensure_proper_type
263
+ super
264
+ end
265
+
266
+ # Populate +coder+ with attributes about this record that should be
267
+ # serialized. The structure of +coder+ defined in this method is
268
+ # guaranteed to match the structure of +coder+ passed to the +init_with+
269
+ # method.
270
+ #
271
+ # Example:
272
+ #
273
+ # class Post < ActiveRecord::Base
274
+ # end
275
+ # coder = {}
276
+ # Post.new.encode_with(coder)
277
+ # coder # => {"attributes" => {"id" => nil, ... }}
278
+ def encode_with(coder)
279
+ coder['attributes'] = attributes_for_coder
280
+ end
281
+
282
+ # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
283
+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
284
+ #
285
+ # Note that new records are different from any other record by definition, unless the
286
+ # other record is the receiver itself. Besides, if you fetch existing records with
287
+ # +select+ and leave the ID out, you're on your own, this predicate will return false.
288
+ #
289
+ # Note also that destroying a record preserves its ID in the model instance, so deleted
290
+ # models are still comparable.
291
+ def ==(comparison_object)
292
+ super ||
293
+ comparison_object.instance_of?(self.class) &&
294
+ id.present? &&
295
+ comparison_object.id == id
296
+ end
297
+ alias :eql? :==
298
+
299
+ # Delegates to id in order to allow two records of the same type and id to work with something like:
300
+ # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
301
+ def hash
302
+ id.hash
303
+ end
304
+
305
+ # Clone and freeze the attributes hash such that associations are still
306
+ # accessible, even on destroyed records, but cloned models will not be
307
+ # frozen.
308
+ def freeze
309
+ @attributes = @attributes.clone.freeze
310
+ self
311
+ end
312
+
313
+ # Returns +true+ if the attributes hash has been frozen.
314
+ def frozen?
315
+ @attributes.frozen?
316
+ end
317
+
318
+ # Allows sort on objects
319
+ def <=>(other_object)
320
+ if other_object.is_a?(self.class)
321
+ self.to_key <=> other_object.to_key
322
+ end
323
+ end
324
+
325
+ # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
326
+ # attributes will be marked as read only since they cannot be saved.
327
+ def readonly?
328
+ @readonly
329
+ end
330
+
331
+ # Marks this record as read only.
332
+ def readonly!
333
+ @readonly = true
334
+ end
335
+
336
+ # Returns the connection currently associated with the class. This can
337
+ # also be used to "borrow" the connection to do database work that isn't
338
+ # easily done without going straight to SQL.
339
+ def connection
340
+ ActiveSupport::Deprecation.warn("#connection is deprecated in favour of accessing it via the class")
341
+ self.class.connection
342
+ end
343
+
344
+ def connection_handler
345
+ self.class.connection_handler
346
+ end
347
+
348
+ # Returns the contents of the record as a nicely formatted string.
349
+ def inspect
350
+ # We check defined?(@attributes) not to issue warnings if the object is
351
+ # allocated but not initialized.
352
+ inspection = if defined?(@attributes) && @attributes
353
+ self.class.column_names.collect { |name|
354
+ if has_attribute?(name)
355
+ "#{name}: #{attribute_for_inspect(name)}"
356
+ end
357
+ }.compact.join(", ")
358
+ else
359
+ "not initialized"
360
+ end
361
+ "#<#{self.class} #{inspection}>"
362
+ end
363
+
364
+ # Returns a hash of the given methods with their names as keys and returned values as values.
365
+ def slice(*methods)
366
+ Hash[methods.map { |method| [method, public_send(method)] }].with_indifferent_access
367
+ end
368
+
369
+ def set_transaction_state(state) # :nodoc:
370
+ @transaction_state = state
371
+ end
372
+
373
+ def has_transactional_callbacks? # :nodoc:
374
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty?
375
+ end
376
+
377
+ # Required to deserialize Syck properly.
378
+ if YAML.const_defined?(:ENGINE) && YAML::ENGINE.syck?
379
+ ActiveSupport::Deprecation.warn(
380
+ "Syck is deprecated and support for serialization has been removed." \
381
+ " ActiveRecord::Core#yaml_initialize will be removed in 4.1 which will break deserialization support with Syck."
382
+ )
383
+ def yaml_initialize(tag, coder) # :nodoc:
384
+ init_with(coder)
385
+ end
386
+ end
387
+
388
+ private
389
+
390
+ # Updates the attributes on this particular ActiveRecord object so that
391
+ # if it is associated with a transaction, then the state of the AR object
392
+ # will be updated to reflect the current state of the transaction
393
+ #
394
+ # The @transaction_state variable stores the states of the associated
395
+ # transaction. This relies on the fact that a transaction can only be in
396
+ # one rollback or commit (otherwise a list of states would be required)
397
+ # Each AR object inside of a transaction carries that transaction's
398
+ # TransactionState.
399
+ #
400
+ # This method checks to see if the ActiveRecord object's state reflects
401
+ # the TransactionState, and rolls back or commits the ActiveRecord object
402
+ # as appropriate.
403
+ #
404
+ # Since ActiveRecord objects can be inside multiple transactions, this
405
+ # method recursively goes through the parent of the TransactionState and
406
+ # checks if the ActiveRecord object reflects the state of the object.
407
+ def sync_with_transaction_state
408
+ update_attributes_from_transaction_state(@transaction_state, 0)
409
+ end
410
+
411
+ def update_attributes_from_transaction_state(transaction_state, depth)
412
+ if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
413
+ unless @reflects_state[depth]
414
+ restore_transaction_record_state if transaction_state.rolledback?
415
+ clear_transaction_record_state
416
+ @reflects_state[depth] = true
417
+ end
418
+
419
+ if transaction_state.parent && !@reflects_state[depth+1]
420
+ update_attributes_from_transaction_state(transaction_state.parent, depth+1)
421
+ end
422
+ end
423
+ end
424
+
425
+ # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
426
+ # of the array, and then rescues from the possible NoMethodError. If those elements are
427
+ # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
428
+ # which significantly impacts upon performance.
429
+ #
430
+ # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
431
+ #
432
+ # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
433
+ def to_ary # :nodoc:
434
+ nil
435
+ end
436
+
437
+ def init_internals
438
+ pk = self.class.primary_key
439
+ @attributes[pk] = nil unless @attributes.key?(pk)
440
+
441
+ @aggregation_cache = {}
442
+ @association_cache = {}
443
+ @attributes_cache = {}
444
+ @previously_changed = {}
445
+ @changed_attributes = {}
446
+ @readonly = false
447
+ @destroyed = false
448
+ @marked_for_destruction = false
449
+ @destroyed_by_association = nil
450
+ @new_record = true
451
+ @txn = nil
452
+ @_start_transaction_state = {}
453
+ @transaction_state = nil
454
+ @reflects_state = [false]
455
+ end
456
+
457
+ def init_changed_attributes
458
+ # Intentionally avoid using #column_defaults since overridden defaults (as is done in
459
+ # optimistic locking) won't get written unless they get marked as changed
460
+ self.class.columns.each do |c|
461
+ attr, orig_value = c.name, c.default
462
+ @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
463
+ end
464
+ end
465
+
466
+ # This method is needed to make protected_attributes gem easier to hook.
467
+ # Remove it when we drop support to this gem.
468
+ def init_attributes(attributes, options)
469
+ assign_attributes(attributes)
470
+ end
471
+ end
472
+ end