sskirby-activerecord 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)