sskirby-activerecord 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG.md +6749 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +222 -0
  4. data/examples/associations.png +0 -0
  5. data/examples/performance.rb +177 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record.rb +147 -0
  8. data/lib/active_record/aggregations.rb +255 -0
  9. data/lib/active_record/associations.rb +1604 -0
  10. data/lib/active_record/associations/alias_tracker.rb +79 -0
  11. data/lib/active_record/associations/association.rb +239 -0
  12. data/lib/active_record/associations/association_scope.rb +119 -0
  13. data/lib/active_record/associations/belongs_to_association.rb +79 -0
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +34 -0
  15. data/lib/active_record/associations/builder/association.rb +55 -0
  16. data/lib/active_record/associations/builder/belongs_to.rb +85 -0
  17. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  19. data/lib/active_record/associations/builder/has_many.rb +71 -0
  20. data/lib/active_record/associations/builder/has_one.rb +62 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  22. data/lib/active_record/associations/collection_association.rb +574 -0
  23. data/lib/active_record/associations/collection_proxy.rb +132 -0
  24. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +62 -0
  25. data/lib/active_record/associations/has_many_association.rb +108 -0
  26. data/lib/active_record/associations/has_many_through_association.rb +180 -0
  27. data/lib/active_record/associations/has_one_association.rb +73 -0
  28. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  29. data/lib/active_record/associations/join_dependency.rb +214 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +154 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  33. data/lib/active_record/associations/join_helper.rb +55 -0
  34. data/lib/active_record/associations/preloader.rb +177 -0
  35. data/lib/active_record/associations/preloader/association.rb +127 -0
  36. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  37. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  38. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  39. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  40. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  41. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  42. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  43. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  44. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  45. data/lib/active_record/associations/singular_association.rb +64 -0
  46. data/lib/active_record/associations/through_association.rb +83 -0
  47. data/lib/active_record/attribute_assignment.rb +221 -0
  48. data/lib/active_record/attribute_methods.rb +272 -0
  49. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  50. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  51. data/lib/active_record/attribute_methods/dirty.rb +101 -0
  52. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  53. data/lib/active_record/attribute_methods/query.rb +39 -0
  54. data/lib/active_record/attribute_methods/read.rb +135 -0
  55. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  56. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -0
  57. data/lib/active_record/attribute_methods/write.rb +69 -0
  58. data/lib/active_record/autosave_association.rb +422 -0
  59. data/lib/active_record/base.rb +716 -0
  60. data/lib/active_record/callbacks.rb +275 -0
  61. data/lib/active_record/coders/yaml_column.rb +41 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +188 -0
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +58 -0
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +388 -0
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -0
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +115 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +492 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +598 -0
  70. data/lib/active_record/connection_adapters/abstract_adapter.rb +296 -0
  71. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  72. data/lib/active_record/connection_adapters/column.rb +270 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +288 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +426 -0
  75. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1261 -0
  76. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -0
  78. data/lib/active_record/connection_adapters/sqlite_adapter.rb +577 -0
  79. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  80. data/lib/active_record/counter_cache.rb +119 -0
  81. data/lib/active_record/dynamic_finder_match.rb +56 -0
  82. data/lib/active_record/dynamic_matchers.rb +79 -0
  83. data/lib/active_record/dynamic_scope_match.rb +23 -0
  84. data/lib/active_record/errors.rb +195 -0
  85. data/lib/active_record/explain.rb +85 -0
  86. data/lib/active_record/explain_subscriber.rb +21 -0
  87. data/lib/active_record/fixtures.rb +906 -0
  88. data/lib/active_record/fixtures/file.rb +65 -0
  89. data/lib/active_record/identity_map.rb +156 -0
  90. data/lib/active_record/inheritance.rb +167 -0
  91. data/lib/active_record/integration.rb +49 -0
  92. data/lib/active_record/locale/en.yml +40 -0
  93. data/lib/active_record/locking/optimistic.rb +183 -0
  94. data/lib/active_record/locking/pessimistic.rb +77 -0
  95. data/lib/active_record/log_subscriber.rb +68 -0
  96. data/lib/active_record/migration.rb +765 -0
  97. data/lib/active_record/migration/command_recorder.rb +105 -0
  98. data/lib/active_record/model_schema.rb +366 -0
  99. data/lib/active_record/nested_attributes.rb +469 -0
  100. data/lib/active_record/observer.rb +121 -0
  101. data/lib/active_record/persistence.rb +372 -0
  102. data/lib/active_record/query_cache.rb +74 -0
  103. data/lib/active_record/querying.rb +58 -0
  104. data/lib/active_record/railtie.rb +119 -0
  105. data/lib/active_record/railties/console_sandbox.rb +6 -0
  106. data/lib/active_record/railties/controller_runtime.rb +49 -0
  107. data/lib/active_record/railties/databases.rake +620 -0
  108. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  109. data/lib/active_record/readonly_attributes.rb +26 -0
  110. data/lib/active_record/reflection.rb +534 -0
  111. data/lib/active_record/relation.rb +534 -0
  112. data/lib/active_record/relation/batches.rb +90 -0
  113. data/lib/active_record/relation/calculations.rb +354 -0
  114. data/lib/active_record/relation/delegation.rb +49 -0
  115. data/lib/active_record/relation/finder_methods.rb +398 -0
  116. data/lib/active_record/relation/predicate_builder.rb +58 -0
  117. data/lib/active_record/relation/query_methods.rb +417 -0
  118. data/lib/active_record/relation/spawn_methods.rb +148 -0
  119. data/lib/active_record/result.rb +34 -0
  120. data/lib/active_record/sanitization.rb +194 -0
  121. data/lib/active_record/schema.rb +58 -0
  122. data/lib/active_record/schema_dumper.rb +204 -0
  123. data/lib/active_record/scoping.rb +152 -0
  124. data/lib/active_record/scoping/default.rb +142 -0
  125. data/lib/active_record/scoping/named.rb +202 -0
  126. data/lib/active_record/serialization.rb +18 -0
  127. data/lib/active_record/serializers/xml_serializer.rb +202 -0
  128. data/lib/active_record/session_store.rb +358 -0
  129. data/lib/active_record/store.rb +50 -0
  130. data/lib/active_record/test_case.rb +73 -0
  131. data/lib/active_record/timestamp.rb +113 -0
  132. data/lib/active_record/transactions.rb +360 -0
  133. data/lib/active_record/translation.rb +22 -0
  134. data/lib/active_record/validations.rb +83 -0
  135. data/lib/active_record/validations/associated.rb +43 -0
  136. data/lib/active_record/validations/uniqueness.rb +180 -0
  137. data/lib/active_record/version.rb +10 -0
  138. data/lib/rails/generators/active_record.rb +25 -0
  139. data/lib/rails/generators/active_record/migration.rb +15 -0
  140. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  141. data/lib/rails/generators/active_record/migration/templates/migration.rb +31 -0
  142. data/lib/rails/generators/active_record/model/model_generator.rb +43 -0
  143. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  144. data/lib/rails/generators/active_record/model/templates/model.rb +7 -0
  145. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  146. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  147. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  148. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  149. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  150. metadata +242 -0
@@ -0,0 +1,716 @@
1
+ begin
2
+ require 'psych'
3
+ rescue LoadError
4
+ end
5
+
6
+ require 'yaml'
7
+ require 'set'
8
+ require 'thread'
9
+ require 'active_support/benchmarkable'
10
+ require 'active_support/dependencies'
11
+ require 'active_support/descendants_tracker'
12
+ require 'active_support/time'
13
+ require 'active_support/core_ext/class/attribute'
14
+ require 'active_support/core_ext/class/attribute_accessors'
15
+ require 'active_support/core_ext/class/delegating_attributes'
16
+ require 'active_support/core_ext/class/attribute'
17
+ require 'active_support/core_ext/array/extract_options'
18
+ require 'active_support/core_ext/hash/deep_merge'
19
+ require 'active_support/core_ext/hash/indifferent_access'
20
+ require 'active_support/core_ext/hash/slice'
21
+ require 'active_support/core_ext/string/behavior'
22
+ require 'active_support/core_ext/kernel/singleton_class'
23
+ require 'active_support/core_ext/module/delegation'
24
+ require 'active_support/core_ext/module/introspection'
25
+ require 'active_support/core_ext/object/duplicable'
26
+ require 'active_support/core_ext/object/blank'
27
+ require 'active_support/deprecation'
28
+ require 'arel'
29
+ require 'active_record/errors'
30
+ require 'active_record/log_subscriber'
31
+ require 'active_record/explain_subscriber'
32
+
33
+ module ActiveRecord #:nodoc:
34
+ # = Active Record
35
+ #
36
+ # Active Record objects don't specify their attributes directly, but rather infer them from
37
+ # the table definition with which they're linked. Adding, removing, and changing attributes
38
+ # and their type is done directly in the database. Any change is instantly reflected in the
39
+ # Active Record objects. The mapping that binds a given Active Record class to a certain
40
+ # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
41
+ #
42
+ # See the mapping rules in table_name and the full example in link:files/activerecord/README_rdoc.html for more insight.
43
+ #
44
+ # == Creation
45
+ #
46
+ # Active Records accept constructor parameters either in a hash or as a block. The hash
47
+ # method is especially useful when you're receiving the data from somewhere else, like an
48
+ # HTTP request. It works like this:
49
+ #
50
+ # user = User.new(:name => "David", :occupation => "Code Artist")
51
+ # user.name # => "David"
52
+ #
53
+ # You can also use block initialization:
54
+ #
55
+ # user = User.new do |u|
56
+ # u.name = "David"
57
+ # u.occupation = "Code Artist"
58
+ # end
59
+ #
60
+ # And of course you can just create a bare object and specify the attributes after the fact:
61
+ #
62
+ # user = User.new
63
+ # user.name = "David"
64
+ # user.occupation = "Code Artist"
65
+ #
66
+ # == Conditions
67
+ #
68
+ # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
69
+ # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
70
+ # be used for statements that don't involve tainted data. The hash form works much like the array form, except
71
+ # only equality and range is possible. Examples:
72
+ #
73
+ # class User < ActiveRecord::Base
74
+ # def self.authenticate_unsafely(user_name, password)
75
+ # where("user_name = '#{user_name}' AND password = '#{password}'").first
76
+ # end
77
+ #
78
+ # def self.authenticate_safely(user_name, password)
79
+ # where("user_name = ? AND password = ?", user_name, password).first
80
+ # end
81
+ #
82
+ # def self.authenticate_safely_simply(user_name, password)
83
+ # where(:user_name => user_name, :password => password).first
84
+ # end
85
+ # end
86
+ #
87
+ # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query
88
+ # and is thus susceptible to SQL-injection attacks if the <tt>user_name</tt> and +password+
89
+ # parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
90
+ # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+
91
+ # before inserting them in the query, which will ensure that an attacker can't escape the
92
+ # query and fake the login (or worse).
93
+ #
94
+ # When using multiple parameters in the conditions, it can easily become hard to read exactly
95
+ # what the fourth or fifth question mark is supposed to represent. In those cases, you can
96
+ # resort to named bind variables instead. That's done by replacing the question marks with
97
+ # symbols and supplying a hash with values for the matching symbol keys:
98
+ #
99
+ # Company.where(
100
+ # "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' }
102
+ # ).first
103
+ #
104
+ # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
105
+ # operator. For instance:
106
+ #
107
+ # Student.where(:first_name => "Harvey", :status => 1)
108
+ # Student.where(params[:student])
109
+ #
110
+ # A range may be used in the hash to use the SQL BETWEEN operator:
111
+ #
112
+ # Student.where(:grade => 9..12)
113
+ #
114
+ # An array may be used in the hash to use the SQL IN operator:
115
+ #
116
+ # Student.where(:grade => [9,11,12])
117
+ #
118
+ # When joining tables, nested hashes or keys written in the form 'table_name.column_name'
119
+ # can be used to qualify the table name of a particular condition. For instance:
120
+ #
121
+ # Student.joins(:schools).where(:schools => { :category => 'public' })
122
+ # Student.joins(:schools).where('schools.category' => 'public' )
123
+ #
124
+ # == Overwriting default accessors
125
+ #
126
+ # All column values are automatically available through basic accessors on the Active Record
127
+ # object, but sometimes you want to specialize this behavior. This can be done by overwriting
128
+ # the default accessors (using the same name as the attribute) and calling
129
+ # <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually
130
+ # change things.
131
+ #
132
+ # class Song < ActiveRecord::Base
133
+ # # Uses an integer of seconds to hold the length of the song
134
+ #
135
+ # def length=(minutes)
136
+ # write_attribute(:length, minutes.to_i * 60)
137
+ # end
138
+ #
139
+ # def length
140
+ # read_attribute(:length) / 60
141
+ # end
142
+ # end
143
+ #
144
+ # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
145
+ # instead of <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
146
+ #
147
+ # == Attribute query methods
148
+ #
149
+ # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
150
+ # Query methods allow you to test whether an attribute value is present.
151
+ #
152
+ # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
153
+ # to determine whether the user has a name:
154
+ #
155
+ # user = User.new(:name => "David")
156
+ # user.name? # => true
157
+ #
158
+ # anonymous = User.new(:name => "")
159
+ # anonymous.name? # => false
160
+ #
161
+ # == Accessing attributes before they have been typecasted
162
+ #
163
+ # Sometimes you want to be able to read the raw attribute data without having the column-determined
164
+ # typecast run its course first. That can be done by using the <tt><attribute>_before_type_cast</tt>
165
+ # accessors that all attributes have. For example, if your Account model has a <tt>balance</tt> attribute,
166
+ # you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
167
+ #
168
+ # This is especially useful in validation situations where the user might supply a string for an
169
+ # integer field and you want to display the original string back in an error message. Accessing the
170
+ # attribute normally would typecast the string to 0, which isn't what you want.
171
+ #
172
+ # == Dynamic attribute-based finders
173
+ #
174
+ # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
175
+ # 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>.
182
+ #
183
+ # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
184
+ # <tt>ActiveRecord::RecordNotFound</tt> error if they do not return any records,
185
+ # like <tt>Person.find_by_last_name!</tt>.
186
+ #
187
+ # It's also possible to use multiple attributes in the same find by separating them with "_and_".
188
+ #
189
+ # Person.where(:user_name => user_name, :password => password).first
190
+ # Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
191
+ #
192
+ # It's even possible to call these dynamic finder methods on relations and named scopes.
193
+ #
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
+ # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
212
+ # saving it first. Protected attributes won't be set unless they are given in a block.
213
+ #
214
+ # # No 'Winter' tag exists
215
+ # winter = Tag.find_or_initialize_by_name("Winter")
216
+ # winter.persisted? # false
217
+ #
218
+ # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
219
+ # a list of parameters.
220
+ #
221
+ # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
222
+ #
223
+ # That will either find an existing tag named "rails", or create a new one while setting the
224
+ # user that created it.
225
+ #
226
+ # Just like <tt>find_by_*</tt>, you can also use <tt>scoped_by_*</tt> to retrieve data. The good thing about
227
+ # using this feature is that the very first time result is returned using <tt>method_missing</tt> technique
228
+ # but after that the method is declared on the class. Henceforth <tt>method_missing</tt> will not be hit.
229
+ #
230
+ # User.scoped_by_user_name('David')
231
+ #
232
+ # == Saving arrays, hashes, and other non-mappable objects in text columns
233
+ #
234
+ # Active Record can serialize any object in text columns using YAML. To do so, you must
235
+ # specify this with a call to the class method +serialize+.
236
+ # This makes it possible to store arrays, hashes, and other non-mappable objects without doing
237
+ # any additional work.
238
+ #
239
+ # class User < ActiveRecord::Base
240
+ # serialize :preferences
241
+ # end
242
+ #
243
+ # user = User.create(:preferences => { "background" => "black", "display" => large })
244
+ # User.find(user.id).preferences # => { "background" => "black", "display" => large }
245
+ #
246
+ # You can also specify a class option as the second parameter that'll raise an exception
247
+ # if a serialized object is retrieved as a descendant of a class not in the hierarchy.
248
+ #
249
+ # class User < ActiveRecord::Base
250
+ # serialize :preferences, Hash
251
+ # end
252
+ #
253
+ # user = User.create(:preferences => %w( one two three ))
254
+ # User.find(user.id).preferences # raises SerializationTypeMismatch
255
+ #
256
+ # When you specify a class option, the default value for that attribute will be a new
257
+ # instance of that class.
258
+ #
259
+ # class User < ActiveRecord::Base
260
+ # serialize :preferences, OpenStruct
261
+ # end
262
+ #
263
+ # user = User.new
264
+ # user.preferences.theme_color = "red"
265
+ #
266
+ #
267
+ # == Single table inheritance
268
+ #
269
+ # Active Record allows inheritance by storing the name of the class in a column that by
270
+ # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
271
+ # This means that an inheritance looking like this:
272
+ #
273
+ # class Company < ActiveRecord::Base; end
274
+ # class Firm < Company; end
275
+ # class Client < Company; end
276
+ # class PriorityClient < Client; end
277
+ #
278
+ # When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in
279
+ # the companies table with type = "Firm". You can then fetch this row again using
280
+ # <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
281
+ #
282
+ # If you don't have a type column defined in your table, single-table inheritance won't
283
+ # be triggered. In that case, it'll work just like normal subclasses with no special magic
284
+ # for differentiating between them or reloading the right type with find.
285
+ #
286
+ # Note, all the attributes for all the cases are kept in the same table. Read more:
287
+ # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
288
+ #
289
+ # == Connection to multiple databases in different models
290
+ #
291
+ # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved
292
+ # by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this
293
+ # connection. But you can also set a class-specific connection. For example, if Course is an
294
+ # ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
295
+ # and Course and all of its subclasses will use this connection instead.
296
+ #
297
+ # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is
298
+ # a Hash indexed by the class. If a connection is requested, the retrieve_connection method
299
+ # will go up the class-hierarchy until a connection is found in the connection pool.
300
+ #
301
+ # == Exceptions
302
+ #
303
+ # * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record.
304
+ # * AdapterNotSpecified - The configuration hash used in <tt>establish_connection</tt> didn't include an
305
+ # <tt>:adapter</tt> key.
306
+ # * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a
307
+ # non-existent adapter
308
+ # (or a bad spelling of an existing one).
309
+ # * AssociationTypeMismatch - The object assigned to the association wasn't of the type
310
+ # specified in the association definition.
311
+ # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
312
+ # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt>
313
+ # before querying.
314
+ # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
315
+ # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
316
+ # nothing was found, please check its documentation for further details.
317
+ # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
318
+ # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
319
+ # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
320
+ # AttributeAssignmentError
321
+ # objects that should be inspected to determine which attributes triggered the errors.
322
+ # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
323
+ # <tt>attributes=</tt> method.
324
+ # You can inspect the +attribute+ property of the exception object to determine which attribute
325
+ # triggered the error.
326
+ #
327
+ # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
328
+ # So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
329
+ # instances in the current object space.
330
+ class Base
331
+ ##
332
+ # :singleton-method:
333
+ # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class,
334
+ # which is then passed on to any new database connections made and which can be retrieved on both
335
+ # a class and instance level by calling +logger+.
336
+ cattr_accessor :logger, :instance_writer => false
337
+
338
+ ##
339
+ # :singleton-method:
340
+ # Contains the database configuration - as is typically stored in config/database.yml -
341
+ # as a Hash.
342
+ #
343
+ # For example, the following database.yml...
344
+ #
345
+ # development:
346
+ # adapter: sqlite3
347
+ # database: db/development.sqlite3
348
+ #
349
+ # production:
350
+ # adapter: sqlite3
351
+ # database: db/production.sqlite3
352
+ #
353
+ # ...would result in ActiveRecord::Base.configurations to look like this:
354
+ #
355
+ # {
356
+ # 'development' => {
357
+ # 'adapter' => 'sqlite3',
358
+ # 'database' => 'db/development.sqlite3'
359
+ # },
360
+ # 'production' => {
361
+ # 'adapter' => 'sqlite3',
362
+ # 'database' => 'db/production.sqlite3'
363
+ # }
364
+ # }
365
+ cattr_accessor :configurations, :instance_writer => false
366
+ @@configurations = {}
367
+
368
+ ##
369
+ # :singleton-method:
370
+ # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
371
+ # dates and times from the database. This is set to :local by default.
372
+ cattr_accessor :default_timezone, :instance_writer => false
373
+ @@default_timezone = :local
374
+
375
+ ##
376
+ # :singleton-method:
377
+ # Specifies the format to use when dumping the database schema with Rails'
378
+ # Rakefile. If :sql, the schema is dumped as (potentially database-
379
+ # specific) SQL statements. If :ruby, the schema is dumped as an
380
+ # ActiveRecord::Schema file which can be loaded into any database that
381
+ # supports migrations. Use :ruby if you want to have different database
382
+ # adapters for, e.g., your development and test environments.
383
+ cattr_accessor :schema_format , :instance_writer => false
384
+ @@schema_format = :ruby
385
+
386
+ ##
387
+ # :singleton-method:
388
+ # Specify whether or not to use timestamps for migration versions
389
+ cattr_accessor :timestamped_migrations , :instance_writer => false
390
+ @@timestamped_migrations = true
391
+
392
+ class << self # Class methods
393
+ def inherited(child_class) #:nodoc:
394
+ child_class.initialize_generated_modules
395
+ super
396
+ end
397
+
398
+ def initialize_generated_modules #:nodoc:
399
+ @attribute_methods_mutex = Mutex.new
400
+
401
+ # force attribute methods to be higher in inheritance hierarchy than other generated methods
402
+ generated_attribute_methods
403
+ generated_feature_methods
404
+ end
405
+
406
+ def generated_feature_methods
407
+ @generated_feature_methods ||= begin
408
+ mod = const_set(:GeneratedFeatureMethods, Module.new)
409
+ include mod
410
+ mod
411
+ end
412
+ end
413
+
414
+ # Returns a string like 'Post(id:integer, title:string, body:text)'
415
+ def inspect
416
+ if self == Base
417
+ super
418
+ elsif abstract_class?
419
+ "#{super}(abstract)"
420
+ elsif table_exists?
421
+ attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
422
+ "#{super}(#{attr_list})"
423
+ else
424
+ "#{super}(Table doesn't exist)"
425
+ end
426
+ end
427
+
428
+ # Overwrite the default class equality method to provide support for association proxies.
429
+ def ===(object)
430
+ object.is_a?(self)
431
+ end
432
+
433
+ def arel_table
434
+ @arel_table ||= Arel::Table.new(table_name, arel_engine)
435
+ end
436
+
437
+ def arel_engine
438
+ @arel_engine ||= begin
439
+ if self == ActiveRecord::Base
440
+ ActiveRecord::Base
441
+ else
442
+ connection_handler.connection_pools[name] ? self : superclass.arel_engine
443
+ end
444
+ end
445
+ end
446
+
447
+ private
448
+
449
+ def relation #:nodoc:
450
+ @relation ||= Relation.new(self, arel_table)
451
+
452
+ if finder_needs_type_condition?
453
+ @relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
454
+ else
455
+ @relation
456
+ end
457
+ end
458
+ end
459
+
460
+ public
461
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
462
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
463
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
464
+ # hence you can't have attributes that aren't part of the table columns.
465
+ #
466
+ # +initialize+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
467
+ # in the +options+ parameter.
468
+ #
469
+ # ==== Examples
470
+ # # Instantiates a single new object
471
+ # User.new(:first_name => 'Jamie')
472
+ #
473
+ # # Instantiates a single new object using the :admin mass-assignment security role
474
+ # User.new({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
475
+ #
476
+ # # Instantiates a single new object bypassing mass-assignment security
477
+ # User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
478
+ def initialize(attributes = nil, options = {})
479
+ @attributes = self.class.initialize_attributes(self.class.column_defaults.dup)
480
+ @association_cache = {}
481
+ @aggregation_cache = {}
482
+ @attributes_cache = {}
483
+ @new_record = true
484
+ @readonly = false
485
+ @destroyed = false
486
+ @marked_for_destruction = false
487
+ @previously_changed = {}
488
+ @changed_attributes = {}
489
+ @relation = nil
490
+
491
+ ensure_proper_type
492
+
493
+ populate_with_current_scope_attributes
494
+
495
+ assign_attributes(attributes, options) if attributes
496
+
497
+ yield self if block_given?
498
+ run_callbacks :initialize
499
+ end
500
+
501
+ # Initialize an empty model object from +coder+. +coder+ must contain
502
+ # the attributes necessary for initializing an empty model object. For
503
+ # example:
504
+ #
505
+ # class Post < ActiveRecord::Base
506
+ # end
507
+ #
508
+ # post = Post.allocate
509
+ # post.init_with('attributes' => { 'title' => 'hello world' })
510
+ # post.title # => 'hello world'
511
+ def init_with(coder)
512
+ @attributes = self.class.initialize_attributes(coder['attributes'])
513
+ @relation = nil
514
+
515
+ @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
516
+ @association_cache = {}
517
+ @aggregation_cache = {}
518
+ @readonly = @destroyed = @marked_for_destruction = false
519
+ @new_record = false
520
+ run_callbacks :find
521
+ run_callbacks :initialize
522
+
523
+ self
524
+ end
525
+
526
+ # Duped objects have no id assigned and are treated as new records. Note
527
+ # that this is a "shallow" copy as it copies the object's attributes
528
+ # only, not its associations. The extent of a "deep" copy is application
529
+ # specific and is therefore left to the application to implement according
530
+ # to its need.
531
+ # The dup method does not preserve the timestamps (created|updated)_(at|on).
532
+ def initialize_dup(other)
533
+ cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
534
+ cloned_attributes.delete(self.class.primary_key)
535
+
536
+ @attributes = cloned_attributes
537
+
538
+ _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks)
539
+
540
+ @changed_attributes = {}
541
+ self.class.column_defaults.each do |attr, orig_value|
542
+ @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr])
543
+ end
544
+
545
+ @aggregation_cache = {}
546
+ @association_cache = {}
547
+ @attributes_cache = {}
548
+ @new_record = true
549
+
550
+ ensure_proper_type
551
+ populate_with_current_scope_attributes
552
+ super
553
+ end
554
+
555
+ # Backport dup from 1.9 so that initialize_dup() gets called
556
+ unless Object.respond_to?(:initialize_dup)
557
+ def dup # :nodoc:
558
+ copy = super
559
+ copy.initialize_dup(self)
560
+ copy
561
+ end
562
+ end
563
+
564
+ # Populate +coder+ with attributes about this record that should be
565
+ # serialized. The structure of +coder+ defined in this method is
566
+ # guaranteed to match the structure of +coder+ passed to the +init_with+
567
+ # method.
568
+ #
569
+ # Example:
570
+ #
571
+ # class Post < ActiveRecord::Base
572
+ # end
573
+ # coder = {}
574
+ # Post.new.encode_with(coder)
575
+ # coder # => { 'id' => nil, ... }
576
+ def encode_with(coder)
577
+ coder['attributes'] = attributes
578
+ end
579
+
580
+ # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
581
+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
582
+ #
583
+ # Note that new records are different from any other record by definition, unless the
584
+ # other record is the receiver itself. Besides, if you fetch existing records with
585
+ # +select+ and leave the ID out, you're on your own, this predicate will return false.
586
+ #
587
+ # Note also that destroying a record preserves its ID in the model instance, so deleted
588
+ # models are still comparable.
589
+ def ==(comparison_object)
590
+ super ||
591
+ comparison_object.instance_of?(self.class) &&
592
+ id.present? &&
593
+ comparison_object.id == id
594
+ end
595
+ alias :eql? :==
596
+
597
+ # Delegates to id in order to allow two records of the same type and id to work with something like:
598
+ # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
599
+ def hash
600
+ id.hash
601
+ end
602
+
603
+ # Freeze the attributes hash such that associations are still accessible, even on destroyed records.
604
+ def freeze
605
+ @attributes.freeze; self
606
+ end
607
+
608
+ # Returns +true+ if the attributes hash has been frozen.
609
+ def frozen?
610
+ @attributes.frozen?
611
+ end
612
+
613
+ # Allows sort on objects
614
+ def <=>(other_object)
615
+ if other_object.is_a?(self.class)
616
+ self.to_key <=> other_object.to_key
617
+ else
618
+ nil
619
+ end
620
+ end
621
+
622
+ # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
623
+ # attributes will be marked as read only since they cannot be saved.
624
+ def readonly?
625
+ @readonly
626
+ end
627
+
628
+ # Marks this record as read only.
629
+ def readonly!
630
+ @readonly = true
631
+ end
632
+
633
+ # Returns the contents of the record as a nicely formatted string.
634
+ def inspect
635
+ inspection = if @attributes
636
+ self.class.column_names.collect { |name|
637
+ if has_attribute?(name)
638
+ "#{name}: #{attribute_for_inspect(name)}"
639
+ end
640
+ }.compact.join(", ")
641
+ else
642
+ "not initialized"
643
+ end
644
+ "#<#{self.class} #{inspection}>"
645
+ end
646
+
647
+ # Hackery to accomodate Syck. Remove for 4.0.
648
+ def to_yaml(opts = {}) #:nodoc:
649
+ if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
650
+ super
651
+ else
652
+ coder = {}
653
+ encode_with(coder)
654
+ YAML.quick_emit(self, opts) do |out|
655
+ out.map(taguri, to_yaml_style) do |map|
656
+ coder.each { |k, v| map.add(k, v) }
657
+ end
658
+ end
659
+ end
660
+ end
661
+
662
+ # Hackery to accomodate Syck. Remove for 4.0.
663
+ def yaml_initialize(tag, coder) #:nodoc:
664
+ init_with(coder)
665
+ end
666
+
667
+ private
668
+
669
+ # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
670
+ # of the array, and then rescues from the possible NoMethodError. If those elements are
671
+ # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
672
+ # which significantly impacts upon performance.
673
+ #
674
+ # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
675
+ #
676
+ # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
677
+ def to_ary # :nodoc:
678
+ nil
679
+ end
680
+
681
+ include ActiveRecord::Persistence
682
+ extend ActiveModel::Naming
683
+ extend QueryCache::ClassMethods
684
+ extend ActiveSupport::Benchmarkable
685
+ extend ActiveSupport::DescendantsTracker
686
+
687
+ extend Querying
688
+ include ReadonlyAttributes
689
+ include ModelSchema
690
+ extend Translation
691
+ include Inheritance
692
+ include Scoping
693
+ extend DynamicMatchers
694
+ include Sanitization
695
+ include Integration
696
+ include AttributeAssignment
697
+ include ActiveModel::Conversion
698
+ include Validations
699
+ extend CounterCache
700
+ include Locking::Optimistic, Locking::Pessimistic
701
+ include AttributeMethods
702
+ include Callbacks, ActiveModel::Observing, Timestamp
703
+ include Associations
704
+ include IdentityMap
705
+ include ActiveModel::SecurePassword
706
+ extend Explain
707
+
708
+ # AutosaveAssociation needs to be included before Transactions, because we want
709
+ # #save_with_autosave_associations to be wrapped inside a transaction.
710
+ include AutosaveAssociation, NestedAttributes
711
+ include Aggregations, Transactions, Reflection, Serialization, Store
712
+ end
713
+ end
714
+
715
+ require 'active_record/connection_adapters/abstract/connection_specification'
716
+ ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)