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
@@ -1,30 +1,19 @@
1
- begin
2
- require 'psych'
3
- rescue LoadError
4
- end
5
-
6
1
  require 'yaml'
7
2
  require 'set'
8
- require 'thread'
9
3
  require 'active_support/benchmarkable'
10
4
  require 'active_support/dependencies'
11
5
  require 'active_support/descendants_tracker'
12
6
  require 'active_support/time'
13
- require 'active_support/core_ext/class/attribute'
14
7
  require 'active_support/core_ext/class/attribute_accessors'
15
8
  require 'active_support/core_ext/class/delegating_attributes'
16
- require 'active_support/core_ext/class/attribute'
17
9
  require 'active_support/core_ext/array/extract_options'
18
10
  require 'active_support/core_ext/hash/deep_merge'
19
- require 'active_support/core_ext/hash/indifferent_access'
20
11
  require 'active_support/core_ext/hash/slice'
21
12
  require 'active_support/core_ext/string/behavior'
22
13
  require 'active_support/core_ext/kernel/singleton_class'
23
- require 'active_support/core_ext/module/delegation'
24
14
  require 'active_support/core_ext/module/introspection'
25
15
  require 'active_support/core_ext/object/duplicable'
26
- require 'active_support/core_ext/object/blank'
27
- require 'active_support/deprecation'
16
+ require 'active_support/core_ext/class/subclasses'
28
17
  require 'arel'
29
18
  require 'active_record/errors'
30
19
  require 'active_record/log_subscriber'
@@ -47,7 +36,7 @@ module ActiveRecord #:nodoc:
47
36
  # method is especially useful when you're receiving the data from somewhere else, like an
48
37
  # HTTP request. It works like this:
49
38
  #
50
- # user = User.new(:name => "David", :occupation => "Code Artist")
39
+ # user = User.new(name: "David", occupation: "Code Artist")
51
40
  # user.name # => "David"
52
41
  #
53
42
  # You can also use block initialization:
@@ -80,7 +69,7 @@ module ActiveRecord #:nodoc:
80
69
  # end
81
70
  #
82
71
  # def self.authenticate_safely_simply(user_name, password)
83
- # where(:user_name => user_name, :password => password).first
72
+ # where(user_name: user_name, password: password).first
84
73
  # end
85
74
  # end
86
75
  #
@@ -98,27 +87,27 @@ module ActiveRecord #:nodoc:
98
87
  #
99
88
  # Company.where(
100
89
  # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
101
- # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
90
+ # { id: 3, name: "37signals", division: "First", accounting_date: '2005-01-01' }
102
91
  # ).first
103
92
  #
104
93
  # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
105
94
  # operator. For instance:
106
95
  #
107
- # Student.where(:first_name => "Harvey", :status => 1)
96
+ # Student.where(first_name: "Harvey", status: 1)
108
97
  # Student.where(params[:student])
109
98
  #
110
99
  # A range may be used in the hash to use the SQL BETWEEN operator:
111
100
  #
112
- # Student.where(:grade => 9..12)
101
+ # Student.where(grade: 9..12)
113
102
  #
114
103
  # An array may be used in the hash to use the SQL IN operator:
115
104
  #
116
- # Student.where(:grade => [9,11,12])
105
+ # Student.where(grade: [9,11,12])
117
106
  #
118
107
  # When joining tables, nested hashes or keys written in the form 'table_name.column_name'
119
108
  # can be used to qualify the table name of a particular condition. For instance:
120
109
  #
121
- # Student.joins(:schools).where(:schools => { :category => 'public' })
110
+ # Student.joins(:schools).where(schools: { category: 'public' })
122
111
  # Student.joins(:schools).where('schools.category' => 'public' )
123
112
  #
124
113
  # == Overwriting default accessors
@@ -152,10 +141,10 @@ module ActiveRecord #:nodoc:
152
141
  # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
153
142
  # to determine whether the user has a name:
154
143
  #
155
- # user = User.new(:name => "David")
144
+ # user = User.new(name: "David")
156
145
  # user.name? # => true
157
146
  #
158
- # anonymous = User.new(:name => "")
147
+ # anonymous = User.new(name: "")
159
148
  # anonymous.name? # => false
160
149
  #
161
150
  # == Accessing attributes before they have been typecasted
@@ -171,14 +160,11 @@ module ActiveRecord #:nodoc:
171
160
  #
172
161
  # == Dynamic attribute-based finders
173
162
  #
174
- # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
163
+ # Dynamic attribute-based finders are a mildly deprecated way of getting (and/or creating) objects
175
164
  # by simple queries without turning to SQL. They work by appending the name of an attribute
176
- # to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt> and thus produces finders
177
- # like <tt>Person.find_by_user_name</tt>, <tt>Person.find_all_by_last_name</tt>, and
178
- # <tt>Payment.find_by_transaction_id</tt>. Instead of writing
179
- # <tt>Person.where(:user_name => user_name).first</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
180
- # And instead of writing <tt>Person.where(:last_name => last_name).all</tt>, you just do
181
- # <tt>Person.find_all_by_last_name(last_name)</tt>.
165
+ # to <tt>find_by_</tt> like <tt>Person.find_by_user_name</tt>.
166
+ # Instead of writing <tt>Person.find_by(user_name: user_name)</tt>, you can use
167
+ # <tt>Person.find_by_user_name(user_name)</tt>.
182
168
  #
183
169
  # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
184
170
  # <tt>ActiveRecord::RecordNotFound</tt> error if they do not return any records,
@@ -186,51 +172,12 @@ module ActiveRecord #:nodoc:
186
172
  #
187
173
  # It's also possible to use multiple attributes in the same find by separating them with "_and_".
188
174
  #
189
- # Person.where(:user_name => user_name, :password => password).first
175
+ # Person.find_by(user_name: user_name, password: password)
190
176
  # Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
191
177
  #
192
178
  # It's even possible to call these dynamic finder methods on relations and named scopes.
193
179
  #
194
- # Payment.order("created_on").find_all_by_amount(50)
195
- # Payment.pending.find_last_by_amount(100)
196
- #
197
- # The same dynamic finder style can be used to create the object if it doesn't already exist.
198
- # This dynamic finder is called with <tt>find_or_create_by_</tt> and will return the object if
199
- # it already exists and otherwise creates it, then returns it. Protected attributes won't be set
200
- # unless they are given in a block.
201
- #
202
- # # No 'Summer' tag exists
203
- # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
204
- #
205
- # # Now the 'Summer' tag does exist
206
- # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
207
- #
208
- # # Now 'Bob' exist and is an 'admin'
209
- # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
210
- #
211
- # Adding an exclamation point (!) on to the end of <tt>find_or_create_by_</tt> will
212
- # raise an <tt>ActiveRecord::RecordInvalid</tt> error if the new record is invalid.
213
- #
214
- # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
215
- # saving it first. Protected attributes won't be set unless they are given in a block.
216
- #
217
- # # No 'Winter' tag exists
218
- # winter = Tag.find_or_initialize_by_name("Winter")
219
- # winter.persisted? # false
220
- #
221
- # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
222
- # a list of parameters.
223
- #
224
- # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
225
- #
226
- # That will either find an existing tag named "rails", or create a new one while setting the
227
- # user that created it.
228
- #
229
- # Just like <tt>find_by_*</tt>, you can also use <tt>scoped_by_*</tt> to retrieve data. The good thing about
230
- # using this feature is that the very first time result is returned using <tt>method_missing</tt> technique
231
- # but after that the method is declared on the class. Henceforth <tt>method_missing</tt> will not be hit.
232
- #
233
- # User.scoped_by_user_name('David')
180
+ # Payment.order("created_on").find_by_amount(50)
234
181
  #
235
182
  # == Saving arrays, hashes, and other non-mappable objects in text columns
236
183
  #
@@ -243,7 +190,7 @@ module ActiveRecord #:nodoc:
243
190
  # serialize :preferences
244
191
  # end
245
192
  #
246
- # user = User.create(:preferences => { "background" => "black", "display" => large })
193
+ # user = User.create(preferences: { "background" => "black", "display" => large })
247
194
  # User.find(user.id).preferences # => { "background" => "black", "display" => large }
248
195
  #
249
196
  # You can also specify a class option as the second parameter that'll raise an exception
@@ -253,7 +200,7 @@ module ActiveRecord #:nodoc:
253
200
  # serialize :preferences, Hash
254
201
  # end
255
202
  #
256
- # user = User.create(:preferences => %w( one two three ))
203
+ # user = User.create(preferences: %w( one two three ))
257
204
  # User.find(user.id).preferences # raises SerializationTypeMismatch
258
205
  #
259
206
  # When you specify a class option, the default value for that attribute will be a new
@@ -278,9 +225,9 @@ module ActiveRecord #:nodoc:
278
225
  # class Client < Company; end
279
226
  # class PriorityClient < Client; end
280
227
  #
281
- # When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in
228
+ # When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
282
229
  # the companies table with type = "Firm". You can then fetch this row again using
283
- # <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
230
+ # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
284
231
  #
285
232
  # If you don't have a type column defined in your table, single-table inheritance won't
286
233
  # be triggered. In that case, it'll work just like normal subclasses with no special magic
@@ -311,410 +258,66 @@ module ActiveRecord #:nodoc:
311
258
  # (or a bad spelling of an existing one).
312
259
  # * AssociationTypeMismatch - The object assigned to the association wasn't of the type
313
260
  # specified in the association definition.
314
- # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
315
- # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt>
261
+ # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
262
+ # <tt>attributes=</tt> method.
263
+ # You can inspect the +attribute+ property of the exception object to determine which attribute
264
+ # triggered the error.
265
+ # * ConnectionNotEstablished - No connection has been established. Use <tt>establish_connection</tt>
316
266
  # before querying.
317
- # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
318
- # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
319
- # nothing was found, please check its documentation for further details.
320
- # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
321
267
  # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
322
268
  # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
323
269
  # AttributeAssignmentError
324
270
  # objects that should be inspected to determine which attributes triggered the errors.
325
- # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
326
- # <tt>attributes=</tt> method.
327
- # You can inspect the +attribute+ property of the exception object to determine which attribute
328
- # triggered the error.
271
+ # * RecordInvalid - raised by save! and create! when the record is invalid.
272
+ # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
273
+ # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
274
+ # nothing was found, please check its documentation for further details.
275
+ # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
276
+ # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
329
277
  #
330
278
  # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
331
279
  # So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
332
280
  # instances in the current object space.
333
281
  class Base
334
- ##
335
- # :singleton-method:
336
- # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class,
337
- # which is then passed on to any new database connections made and which can be retrieved on both
338
- # a class and instance level by calling +logger+.
339
- cattr_accessor :logger, :instance_writer => false
340
-
341
- ##
342
- # :singleton-method:
343
- # Contains the database configuration - as is typically stored in config/database.yml -
344
- # as a Hash.
345
- #
346
- # For example, the following database.yml...
347
- #
348
- # development:
349
- # adapter: sqlite3
350
- # database: db/development.sqlite3
351
- #
352
- # production:
353
- # adapter: sqlite3
354
- # database: db/production.sqlite3
355
- #
356
- # ...would result in ActiveRecord::Base.configurations to look like this:
357
- #
358
- # {
359
- # 'development' => {
360
- # 'adapter' => 'sqlite3',
361
- # 'database' => 'db/development.sqlite3'
362
- # },
363
- # 'production' => {
364
- # 'adapter' => 'sqlite3',
365
- # 'database' => 'db/production.sqlite3'
366
- # }
367
- # }
368
- cattr_accessor :configurations, :instance_writer => false
369
- @@configurations = {}
370
-
371
- ##
372
- # :singleton-method:
373
- # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
374
- # dates and times from the database. This is set to :local by default.
375
- cattr_accessor :default_timezone, :instance_writer => false
376
- @@default_timezone = :local
377
-
378
- ##
379
- # :singleton-method:
380
- # Specifies the format to use when dumping the database schema with Rails'
381
- # Rakefile. If :sql, the schema is dumped as (potentially database-
382
- # specific) SQL statements. If :ruby, the schema is dumped as an
383
- # ActiveRecord::Schema file which can be loaded into any database that
384
- # supports migrations. Use :ruby if you want to have different database
385
- # adapters for, e.g., your development and test environments.
386
- cattr_accessor :schema_format , :instance_writer => false
387
- @@schema_format = :ruby
388
-
389
- ##
390
- # :singleton-method:
391
- # Specify whether or not to use timestamps for migration versions
392
- cattr_accessor :timestamped_migrations , :instance_writer => false
393
- @@timestamped_migrations = true
394
-
395
- class << self # Class methods
396
- def inherited(child_class) #:nodoc:
397
- child_class.initialize_generated_modules
398
- super
399
- end
400
-
401
- def initialize_generated_modules #:nodoc:
402
- @attribute_methods_mutex = Mutex.new
403
-
404
- # force attribute methods to be higher in inheritance hierarchy than other generated methods
405
- generated_attribute_methods
406
- generated_feature_methods
407
- end
408
-
409
- def generated_feature_methods
410
- @generated_feature_methods ||= begin
411
- mod = const_set(:GeneratedFeatureMethods, Module.new)
412
- include mod
413
- mod
414
- end
415
- end
416
-
417
- # Returns a string like 'Post(id:integer, title:string, body:text)'
418
- def inspect
419
- if self == Base
420
- super
421
- elsif abstract_class?
422
- "#{super}(abstract)"
423
- elsif table_exists?
424
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
425
- "#{super}(#{attr_list})"
426
- else
427
- "#{super}(Table doesn't exist)"
428
- end
429
- end
430
-
431
- # Overwrite the default class equality method to provide support for association proxies.
432
- def ===(object)
433
- object.is_a?(self)
434
- end
435
-
436
- def arel_table
437
- @arel_table ||= Arel::Table.new(table_name, arel_engine)
438
- end
439
-
440
- def arel_engine
441
- @arel_engine ||= begin
442
- if self == ActiveRecord::Base
443
- ActiveRecord::Base
444
- else
445
- connection_handler.retrieve_connection_pool(self) ? self : superclass.arel_engine
446
- end
447
- end
448
- end
449
-
450
- private
451
-
452
- def relation #:nodoc:
453
- relation = Relation.new(self, arel_table)
454
-
455
- if finder_needs_type_condition?
456
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
457
- else
458
- relation
459
- end
460
- end
461
- end
462
-
463
- public
464
- # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
465
- # attributes but not yet saved (pass a hash with key names matching the associated table column names).
466
- # In both instances, valid attribute keys are determined by the column names of the associated table --
467
- # hence you can't have attributes that aren't part of the table columns.
468
- #
469
- # +initialize+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
470
- # in the +options+ parameter.
471
- #
472
- # ==== Examples
473
- # # Instantiates a single new object
474
- # User.new(:first_name => 'Jamie')
475
- #
476
- # # Instantiates a single new object using the :admin mass-assignment security role
477
- # User.new({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
478
- #
479
- # # Instantiates a single new object bypassing mass-assignment security
480
- # User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
481
- def initialize(attributes = nil, options = {})
482
- defaults = Hash[self.class.column_defaults.map { |k, v| [k, v.duplicable? ? v.dup : v] }]
483
- @attributes = self.class.initialize_attributes(defaults)
484
- @association_cache = {}
485
- @aggregation_cache = {}
486
- @attributes_cache = {}
487
- @new_record = true
488
- @readonly = false
489
- @destroyed = false
490
- @marked_for_destruction = false
491
- @previously_changed = {}
492
- @changed_attributes = {}
493
-
494
- ensure_proper_type
495
-
496
- populate_with_current_scope_attributes
497
-
498
- assign_attributes(attributes, options) if attributes
499
-
500
- yield self if block_given?
501
- run_callbacks :initialize
502
- end
503
-
504
- # Initialize an empty model object from +coder+. +coder+ must contain
505
- # the attributes necessary for initializing an empty model object. For
506
- # example:
507
- #
508
- # class Post < ActiveRecord::Base
509
- # end
510
- #
511
- # post = Post.allocate
512
- # post.init_with('attributes' => { 'title' => 'hello world' })
513
- # post.title # => 'hello world'
514
- def init_with(coder)
515
- @attributes = self.class.initialize_attributes(coder['attributes'])
516
- @relation = nil
517
-
518
- @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
519
- @association_cache = {}
520
- @aggregation_cache = {}
521
- @readonly = @destroyed = @marked_for_destruction = false
522
- @new_record = false
523
- run_callbacks :find
524
- run_callbacks :initialize
525
-
526
- self
527
- end
528
-
529
- # Duped objects have no id assigned and are treated as new records. Note
530
- # that this is a "shallow" copy as it copies the object's attributes
531
- # only, not its associations. The extent of a "deep" copy is application
532
- # specific and is therefore left to the application to implement according
533
- # to its need.
534
- # The dup method does not preserve the timestamps (created|updated)_(at|on).
535
- def initialize_dup(other)
536
- cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
537
- self.class.initialize_attributes(cloned_attributes, :serialized => false)
538
-
539
- cloned_attributes.delete(self.class.primary_key)
540
-
541
- @attributes = cloned_attributes
542
-
543
- _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks)
544
-
545
- @changed_attributes = {}
546
- self.class.column_defaults.each do |attr, orig_value|
547
- @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
548
- end
549
-
550
- @aggregation_cache = {}
551
- @association_cache = {}
552
- @attributes_cache = {}
553
- @new_record = true
554
-
555
- ensure_proper_type
556
- super
557
- end
558
-
559
- # Backport dup from 1.9 so that initialize_dup() gets called
560
- unless Object.respond_to?(:initialize_dup, true)
561
- def dup # :nodoc:
562
- copy = super
563
- copy.initialize_dup(self)
564
- copy
565
- end
566
- end
567
-
568
- # Populate +coder+ with attributes about this record that should be
569
- # serialized. The structure of +coder+ defined in this method is
570
- # guaranteed to match the structure of +coder+ passed to the +init_with+
571
- # method.
572
- #
573
- # Example:
574
- #
575
- # class Post < ActiveRecord::Base
576
- # end
577
- # coder = {}
578
- # Post.new.encode_with(coder)
579
- # coder # => { 'id' => nil, ... }
580
- def encode_with(coder)
581
- coder['attributes'] = attributes
582
- end
583
-
584
- # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
585
- # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
586
- #
587
- # Note that new records are different from any other record by definition, unless the
588
- # other record is the receiver itself. Besides, if you fetch existing records with
589
- # +select+ and leave the ID out, you're on your own, this predicate will return false.
590
- #
591
- # Note also that destroying a record preserves its ID in the model instance, so deleted
592
- # models are still comparable.
593
- def ==(comparison_object)
594
- super ||
595
- comparison_object.instance_of?(self.class) &&
596
- id.present? &&
597
- comparison_object.id == id
598
- end
599
- alias :eql? :==
600
-
601
- # Delegates to id in order to allow two records of the same type and id to work with something like:
602
- # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
603
- def hash
604
- id.hash
605
- end
606
-
607
- # Freeze the attributes hash such that associations are still accessible, even on destroyed records.
608
- def freeze
609
- @attributes.freeze; self
610
- end
611
-
612
- # Returns +true+ if the attributes hash has been frozen.
613
- def frozen?
614
- @attributes.frozen?
615
- end
616
-
617
- # Allows sort on objects
618
- def <=>(other_object)
619
- if other_object.is_a?(self.class)
620
- self.to_key <=> other_object.to_key
621
- else
622
- nil
623
- end
624
- end
625
-
626
- # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
627
- # attributes will be marked as read only since they cannot be saved.
628
- def readonly?
629
- @readonly
630
- end
631
-
632
- # Marks this record as read only.
633
- def readonly!
634
- @readonly = true
635
- end
636
-
637
- # Returns the contents of the record as a nicely formatted string.
638
- def inspect
639
- inspection = if @attributes
640
- self.class.column_names.collect { |name|
641
- if has_attribute?(name)
642
- "#{name}: #{attribute_for_inspect(name)}"
643
- end
644
- }.compact.join(", ")
645
- else
646
- "not initialized"
647
- end
648
- "#<#{self.class} #{inspection}>"
649
- end
650
-
651
- # Hackery to accomodate Syck. Remove for 4.0.
652
- def to_yaml(opts = {}) #:nodoc:
653
- if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
654
- super
655
- else
656
- coder = {}
657
- encode_with(coder)
658
- YAML.quick_emit(self, opts) do |out|
659
- out.map(taguri, to_yaml_style) do |map|
660
- coder.each { |k, v| map.add(k, v) }
661
- end
662
- end
663
- end
664
- end
665
-
666
- # Hackery to accomodate Syck. Remove for 4.0.
667
- def yaml_initialize(tag, coder) #:nodoc:
668
- init_with(coder)
669
- end
670
-
671
- private
672
-
673
- # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
674
- # of the array, and then rescues from the possible NoMethodError. If those elements are
675
- # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
676
- # which significantly impacts upon performance.
677
- #
678
- # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
679
- #
680
- # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
681
- def to_ary # :nodoc:
682
- nil
683
- end
684
-
685
- include ActiveRecord::Persistence
686
282
  extend ActiveModel::Naming
687
- extend QueryCache::ClassMethods
283
+
688
284
  extend ActiveSupport::Benchmarkable
689
285
  extend ActiveSupport::DescendantsTracker
690
286
 
287
+ extend ConnectionHandling
288
+ extend QueryCache::ClassMethods
691
289
  extend Querying
290
+ extend Translation
291
+ extend DynamicMatchers
292
+ extend Explain
293
+
294
+ include Persistence
692
295
  include ReadonlyAttributes
693
296
  include ModelSchema
694
- extend Translation
695
297
  include Inheritance
696
298
  include Scoping
697
- extend DynamicMatchers
698
299
  include Sanitization
699
300
  include AttributeAssignment
700
301
  include ActiveModel::Conversion
701
302
  include Integration
702
303
  include Validations
703
- extend CounterCache
704
- include Locking::Optimistic, Locking::Pessimistic
304
+ include CounterCache
305
+ include Locking::Optimistic
306
+ include Locking::Pessimistic
705
307
  include AttributeMethods
706
- include Callbacks, ActiveModel::Observing, Timestamp
308
+ include Callbacks
309
+ include Timestamp
707
310
  include Associations
708
- include IdentityMap
709
311
  include ActiveModel::SecurePassword
710
- extend Explain
711
-
712
- # AutosaveAssociation needs to be included before Transactions, because we want
713
- # #save_with_autosave_associations to be wrapped inside a transaction.
714
- include AutosaveAssociation, NestedAttributes
715
- include Aggregations, Transactions, Reflection, Serialization, Store
312
+ include AutosaveAssociation
313
+ include NestedAttributes
314
+ include Aggregations
315
+ include Transactions
316
+ include Reflection
317
+ include Serialization
318
+ include Store
319
+ include Core
716
320
  end
717
- end
718
321
 
719
- require 'active_record/connection_adapters/abstract/connection_specification'
720
- ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
322
+ ActiveSupport.run_load_hooks(:active_record, Base)
323
+ end