activerecord 3.1.10 → 4.2.11

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.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  # end
23
23
  #
24
24
  # # Comments are not patches, this assignment raises AssociationTypeMismatch.
25
- # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
25
+ # @ticket.patches << Comment.new(content: "Please attach tests to your patch.")
26
26
  class AssociationTypeMismatch < ActiveRecordError
27
27
  end
28
28
 
@@ -30,17 +30,18 @@ module ActiveRecord
30
30
  class SerializationTypeMismatch < ActiveRecordError
31
31
  end
32
32
 
33
- # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt>
34
- # misses adapter field).
33
+ # Raised when adapter not specified on connection (or configuration file
34
+ # +config/database.yml+ misses adapter field).
35
35
  class AdapterNotSpecified < ActiveRecordError
36
36
  end
37
37
 
38
- # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
38
+ # Raised when Active Record cannot find database adapter specified in
39
+ # +config/database.yml+ or programmatically.
39
40
  class AdapterNotFound < ActiveRecordError
40
41
  end
41
42
 
42
- # Raised when connection to the database could not been established (for example when <tt>connection=</tt>
43
- # is given a nil object).
43
+ # Raised when connection to the database could not been established (for
44
+ # example when +connection=+ is given a nil object).
44
45
  class ConnectionNotEstablished < ActiveRecordError
45
46
  end
46
47
 
@@ -51,28 +52,48 @@ module ActiveRecord
51
52
  # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
52
53
  # saved because record is invalid.
53
54
  class RecordNotSaved < ActiveRecordError
54
- end
55
+ attr_reader :record
55
56
 
56
- # Raised when SQL statement cannot be executed by the database (for example, it's often the case for
57
- # MySQL when Ruby driver used is too old).
58
- class StatementInvalid < ActiveRecordError
57
+ def initialize(message, record = nil)
58
+ @record = record
59
+ super(message)
60
+ end
59
61
  end
60
62
 
61
- # Raised when SQL statement is invalid and the application gets a blank result.
62
- class ThrowResult < ActiveRecordError
63
+ # Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
64
+ #
65
+ # begin
66
+ # complex_operation_that_internally_calls_destroy!
67
+ # rescue ActiveRecord::RecordNotDestroyed => invalid
68
+ # puts invalid.record.errors
69
+ # end
70
+ #
71
+ class RecordNotDestroyed < ActiveRecordError
72
+ attr_reader :record
73
+
74
+ def initialize(message, record = nil)
75
+ @record = record
76
+ super(message)
77
+ end
63
78
  end
64
79
 
65
- # Parent class for all specific exceptions which wrap database driver exceptions
66
- # provides access to the original exception also.
67
- class WrappedDatabaseException < StatementInvalid
80
+ # Superclass for all database execution errors.
81
+ #
82
+ # Wraps the underlying database error as +original_exception+.
83
+ class StatementInvalid < ActiveRecordError
68
84
  attr_reader :original_exception
69
85
 
70
- def initialize(message, original_exception)
86
+ def initialize(message, original_exception = nil)
71
87
  super(message)
72
88
  @original_exception = original_exception
73
89
  end
74
90
  end
75
91
 
92
+ # Defunct wrapper class kept for compatibility.
93
+ # +StatementInvalid+ wraps the original exception now.
94
+ class WrappedDatabaseException < StatementInvalid
95
+ end
96
+
76
97
  # Raised when a record cannot be inserted because it would violate a uniqueness constraint.
77
98
  class RecordNotUnique < WrappedDatabaseException
78
99
  end
@@ -81,28 +102,40 @@ module ActiveRecord
81
102
  class InvalidForeignKey < WrappedDatabaseException
82
103
  end
83
104
 
84
- # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example,
85
- # when using +find+ method)
86
- # does not match number of expected variables.
87
- #
88
- # For example, in
105
+ # Raised when number of bind variables in statement given to +:condition+ key
106
+ # (for example, when using +find+ method) does not match number of expected
107
+ # values supplied.
89
108
  #
90
- # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
109
+ # For example, when there are two placeholders with only one value supplied:
91
110
  #
92
- # two placeholders are given but only one variable to fill them.
111
+ # Location.where("lat = ? AND lng = ?", 53.7362)
93
112
  class PreparedStatementInvalid < ActiveRecordError
94
113
  end
95
114
 
115
+ # Raised when a given database does not exist.
116
+ class NoDatabaseError < StatementInvalid
117
+ end
118
+
96
119
  # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
97
120
  # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
98
121
  # the page before the other.
99
122
  #
100
- # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
123
+ # Read more about optimistic locking in ActiveRecord::Locking module
124
+ # documentation.
101
125
  class StaleObjectError < ActiveRecordError
126
+ attr_reader :record, :attempted_action
127
+
128
+ def initialize(record, attempted_action)
129
+ super("Attempted to #{attempted_action} a stale object: #{record.class.name}")
130
+ @record = record
131
+ @attempted_action = attempted_action
132
+ end
133
+
102
134
  end
103
135
 
104
- # Raised when association is being configured improperly or
105
- # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
136
+ # Raised when association is being configured improperly or user tries to use
137
+ # offset and limit together with +has_many+ or +has_and_belongs_to_many+
138
+ # associations.
106
139
  class ConfigurationError < ActiveRecordError
107
140
  end
108
141
 
@@ -140,23 +173,34 @@ module ActiveRecord
140
173
  class Rollback < ActiveRecordError
141
174
  end
142
175
 
143
- # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
176
+ # Raised when attribute has a name reserved by Active Record (when attribute
177
+ # has name of one of Active Record instance methods).
144
178
  class DangerousAttributeError < ActiveRecordError
145
179
  end
146
180
 
147
181
  # Raised when unknown attributes are supplied via mass assignment.
148
182
  class UnknownAttributeError < NoMethodError
183
+
184
+ attr_reader :record, :attribute
185
+
186
+ def initialize(record, attribute)
187
+ @record = record
188
+ @attribute = attribute.to_s
189
+ super("unknown attribute '#{attribute}' for #{@record.class}.")
190
+ end
191
+
149
192
  end
150
193
 
151
194
  # Raised when an error occurred while doing a mass assignment to an attribute through the
152
- # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
195
+ # +attributes=+ method. The exception has an +attribute+ property that is the name of the
153
196
  # offending attribute.
154
197
  class AttributeAssignmentError < ActiveRecordError
155
198
  attr_reader :exception, :attribute
199
+
156
200
  def initialize(message, exception, attribute)
201
+ super(message)
157
202
  @exception = exception
158
203
  @attribute = attribute
159
- @message = message
160
204
  end
161
205
  end
162
206
 
@@ -165,21 +209,45 @@ module ActiveRecord
165
209
  # objects, each corresponding to the error while assigning to an attribute.
166
210
  class MultiparameterAssignmentErrors < ActiveRecordError
167
211
  attr_reader :errors
212
+
168
213
  def initialize(errors)
169
214
  @errors = errors
170
215
  end
171
216
  end
172
217
 
173
- # Raised when a primary key is needed, but there is not one specified in the schema or model.
218
+ # Raised when a primary key is needed, but not specified in the schema or model.
174
219
  class UnknownPrimaryKey < ActiveRecordError
175
220
  attr_reader :model
176
221
 
177
- def initialize(model)
222
+ def initialize(model, description = nil)
223
+ message = "Unknown primary key for table #{model.table_name} in model #{model}."
224
+ message += "\n#{description}" if description
225
+ super(message)
178
226
  @model = model
179
227
  end
228
+ end
180
229
 
181
- def message
182
- "Unknown primary key for table #{model.table_name} in model #{model}."
183
- end
230
+ # Raised when a relation cannot be mutated because it's already loaded.
231
+ #
232
+ # class Task < ActiveRecord::Base
233
+ # end
234
+ #
235
+ # relation = Task.all
236
+ # relation.loaded? # => true
237
+ #
238
+ # # Methods which try to mutate a loaded relation fail.
239
+ # relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation
240
+ # relation.limit!(5) # => ActiveRecord::ImmutableRelation
241
+ class ImmutableRelation < ActiveRecordError
242
+ end
243
+
244
+ # TransactionIsolationError will be raised under the following conditions:
245
+ #
246
+ # * The adapter does not support setting the isolation level
247
+ # * You are joining an existing open transaction
248
+ # * You are creating a nested (savepoint) transaction
249
+ #
250
+ # The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
251
+ class TransactionIsolationError < ActiveRecordError
184
252
  end
185
253
  end
@@ -0,0 +1,38 @@
1
+ require 'active_support/lazy_load_hooks'
2
+ require 'active_record/explain_registry'
3
+
4
+ module ActiveRecord
5
+ module Explain
6
+ # Executes the block with the collect flag enabled. Queries are collected
7
+ # asynchronously by the subscriber and returned.
8
+ def collecting_queries_for_explain # :nodoc:
9
+ ExplainRegistry.collect = true
10
+ yield
11
+ ExplainRegistry.queries
12
+ ensure
13
+ ExplainRegistry.reset
14
+ end
15
+
16
+ # Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
17
+ # Returns a formatted string ready to be logged.
18
+ def exec_explain(queries) # :nodoc:
19
+ str = queries.map do |sql, bind|
20
+ [].tap do |msg|
21
+ msg << "EXPLAIN for: #{sql}"
22
+ unless bind.empty?
23
+ bind_msg = bind.map {|col, val| [col.name, val]}.inspect
24
+ msg.last << " #{bind_msg}"
25
+ end
26
+ msg << connection.explain(sql, bind)
27
+ end.join("\n")
28
+ end.join("\n")
29
+
30
+ # Overriding inspect to be more human readable, especially in the console.
31
+ def str.inspect
32
+ self
33
+ end
34
+
35
+ str
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/per_thread_registry'
2
+
3
+ module ActiveRecord
4
+ # This is a thread locals registry for EXPLAIN. For example
5
+ #
6
+ # ActiveRecord::ExplainRegistry.queries
7
+ #
8
+ # returns the collected queries local to the current thread.
9
+ #
10
+ # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
11
+ # for further details.
12
+ class ExplainRegistry # :nodoc:
13
+ extend ActiveSupport::PerThreadRegistry
14
+
15
+ attr_accessor :queries, :collect
16
+
17
+ def initialize
18
+ reset
19
+ end
20
+
21
+ def collect?
22
+ @collect
23
+ end
24
+
25
+ def reset
26
+ @collect = false
27
+ @queries = []
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ require 'active_support/notifications'
2
+ require 'active_record/explain_registry'
3
+
4
+ module ActiveRecord
5
+ class ExplainSubscriber # :nodoc:
6
+ def start(name, id, payload)
7
+ # unused
8
+ end
9
+
10
+ def finish(name, id, payload)
11
+ if ExplainRegistry.collect? && !ignore_payload?(payload)
12
+ ExplainRegistry.queries << payload.values_at(:sql, :binds)
13
+ end
14
+ end
15
+
16
+ # SCHEMA queries cannot be EXPLAINed, also we do not want to run EXPLAIN on
17
+ # our own EXPLAINs now matter how loopingly beautiful that would be.
18
+ #
19
+ # On the other hand, we want to monitor the performance of our real database
20
+ # queries, not the performance of the access to the query cache.
21
+ IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
22
+ EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
23
+ def ignore_payload?(payload)
24
+ payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
25
+ end
26
+
27
+ ActiveSupport::Notifications.subscribe("sql.active_record", new)
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+
4
+ module ActiveRecord
5
+ class FixtureSet
6
+ class File # :nodoc:
7
+ include Enumerable
8
+
9
+ ##
10
+ # Open a fixture file named +file+. When called with a block, the block
11
+ # is called with the filehandle and the filehandle is automatically closed
12
+ # when the block finishes.
13
+ def self.open(file)
14
+ x = new file
15
+ block_given? ? yield(x) : x
16
+ end
17
+
18
+ def initialize(file)
19
+ @file = file
20
+ @rows = nil
21
+ end
22
+
23
+ def each(&block)
24
+ rows.each(&block)
25
+ end
26
+
27
+
28
+ private
29
+ def rows
30
+ return @rows if @rows
31
+
32
+ begin
33
+ data = YAML.load(render(IO.read(@file)))
34
+ rescue ArgumentError, Psych::SyntaxError => error
35
+ raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
36
+ end
37
+ @rows = data ? validate(data).to_a : []
38
+ end
39
+
40
+ def render(content)
41
+ context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
42
+ ERB.new(content).result(context.get_binding)
43
+ end
44
+
45
+ # Validate our unmarshalled data.
46
+ def validate(data)
47
+ unless Hash === data || YAML::Omap === data
48
+ raise Fixture::FormatError, 'fixture is not a hash'
49
+ end
50
+
51
+ raise Fixture::FormatError unless data.all? { |name, row| Hash === row }
52
+ data
53
+ end
54
+ end
55
+ end
56
+ end