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,40 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class StatementPool
4
+ include Enumerable
5
+
6
+ def initialize(connection, max = 1000)
7
+ @connection = connection
8
+ @max = max
9
+ end
10
+
11
+ def each
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def key?(key)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def [](key)
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def length
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def []=(sql, key)
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def clear
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def delete(key)
36
+ raise NotImplementedError
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,119 @@
1
+ module ActiveRecord
2
+ # = Active Record Counter Cache
3
+ module CounterCache
4
+ # Resets one or more counter caches to their correct value using an SQL
5
+ # count query. This is useful when adding new counter caches, or if the
6
+ # counter has been corrupted or modified directly by SQL.
7
+ #
8
+ # ==== Parameters
9
+ #
10
+ # * +id+ - The id of the object you wish to reset a counter on.
11
+ # * +counters+ - One or more counter names to reset
12
+ #
13
+ # ==== Examples
14
+ #
15
+ # # For Post with id #1 records reset the comments_count
16
+ # Post.reset_counters(1, :comments)
17
+ def reset_counters(id, *counters)
18
+ object = find(id)
19
+ counters.each do |association|
20
+ has_many_association = reflect_on_association(association.to_sym)
21
+
22
+ expected_name = if has_many_association.options[:as]
23
+ has_many_association.options[:as].to_s.classify
24
+ else
25
+ self.name
26
+ end
27
+
28
+ foreign_key = has_many_association.foreign_key.to_s
29
+ child_class = has_many_association.klass
30
+ belongs_to = child_class.reflect_on_all_associations(:belongs_to)
31
+ reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key }
32
+ counter_name = reflection.counter_cache_column
33
+
34
+ stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
35
+ arel_table[counter_name] => object.send(association).count
36
+ })
37
+ connection.update stmt
38
+ end
39
+ return true
40
+ end
41
+
42
+ # A generic "counter updater" implementation, intended primarily to be
43
+ # used by increment_counter and decrement_counter, but which may also
44
+ # be useful on its own. It simply does a direct SQL update for the record
45
+ # with the given ID, altering the given hash of counters by the amount
46
+ # given by the corresponding value:
47
+ #
48
+ # ==== Parameters
49
+ #
50
+ # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
51
+ # * +counters+ - An Array of Hashes containing the names of the fields
52
+ # to update as keys and the amount to update the field by as values.
53
+ #
54
+ # ==== Examples
55
+ #
56
+ # # For the Post with id of 5, decrement the comment_count by 1, and
57
+ # # increment the action_count by 1
58
+ # Post.update_counters 5, :comment_count => -1, :action_count => 1
59
+ # # Executes the following SQL:
60
+ # # UPDATE posts
61
+ # # SET comment_count = COALESCE(comment_count, 0) - 1,
62
+ # # action_count = COALESCE(action_count, 0) + 1
63
+ # # WHERE id = 5
64
+ #
65
+ # # For the Posts with id of 10 and 15, increment the comment_count by 1
66
+ # Post.update_counters [10, 15], :comment_count => 1
67
+ # # Executes the following SQL:
68
+ # # UPDATE posts
69
+ # # SET comment_count = COALESCE(comment_count, 0) + 1
70
+ # # WHERE id IN (10, 15)
71
+ def update_counters(id, counters)
72
+ updates = counters.map do |counter_name, value|
73
+ operator = value < 0 ? '-' : '+'
74
+ quoted_column = connection.quote_column_name(counter_name)
75
+ "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
76
+ end
77
+
78
+ IdentityMap.remove_by_id(symbolized_base_class, id) if IdentityMap.enabled?
79
+
80
+ update_all(updates.join(', '), primary_key => id )
81
+ end
82
+
83
+ # Increment a number field by one, usually representing a count.
84
+ #
85
+ # This is used for caching aggregate values, so that they don't need to be computed every time.
86
+ # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
87
+ # shown it would have to run an SQL query to find how many posts and comments there are.
88
+ #
89
+ # ==== Parameters
90
+ #
91
+ # * +counter_name+ - The name of the field that should be incremented.
92
+ # * +id+ - The id of the object that should be incremented.
93
+ #
94
+ # ==== Examples
95
+ #
96
+ # # Increment the post_count column for the record with an id of 5
97
+ # DiscussionBoard.increment_counter(:post_count, 5)
98
+ def increment_counter(counter_name, id)
99
+ update_counters(id, counter_name => 1)
100
+ end
101
+
102
+ # Decrement a number field by one, usually representing a count.
103
+ #
104
+ # This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
105
+ #
106
+ # ==== Parameters
107
+ #
108
+ # * +counter_name+ - The name of the field that should be decremented.
109
+ # * +id+ - The id of the object that should be decremented.
110
+ #
111
+ # ==== Examples
112
+ #
113
+ # # Decrement the post_count column for the record with an id of 5
114
+ # DiscussionBoard.decrement_counter(:post_count, 5)
115
+ def decrement_counter(counter_name, id)
116
+ update_counters(id, counter_name => -1)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,56 @@
1
+ module ActiveRecord
2
+
3
+ # = Active Record Dynamic Finder Match
4
+ #
5
+ # Refer to ActiveRecord::Base documentation for Dynamic attribute-based finders for detailed info
6
+ #
7
+ class DynamicFinderMatch
8
+ def self.match(method)
9
+ finder = :first
10
+ bang = false
11
+ instantiator = nil
12
+
13
+ case method.to_s
14
+ when /^find_(all_|last_)?by_([_a-zA-Z]\w*)$/
15
+ finder = :last if $1 == 'last_'
16
+ finder = :all if $1 == 'all_'
17
+ names = $2
18
+ when /^find_by_([_a-zA-Z]\w*)\!$/
19
+ bang = true
20
+ names = $1
21
+ when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
22
+ instantiator = $1 == 'initialize' ? :new : :create
23
+ names = $2
24
+ else
25
+ return nil
26
+ end
27
+
28
+ new(finder, instantiator, bang, names.split('_and_'))
29
+ end
30
+
31
+ def initialize(finder, instantiator, bang, attribute_names)
32
+ @finder = finder
33
+ @instantiator = instantiator
34
+ @bang = bang
35
+ @attribute_names = attribute_names
36
+ end
37
+
38
+ attr_reader :finder, :attribute_names, :instantiator
39
+
40
+ def finder?
41
+ @finder && !@instantiator
42
+ end
43
+
44
+ def instantiator?
45
+ @finder == :first && @instantiator
46
+ end
47
+
48
+ def creator?
49
+ @finder == :first && @instantiator == :create
50
+ end
51
+
52
+ def bang?
53
+ @bang
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,79 @@
1
+ module ActiveRecord
2
+ module DynamicMatchers
3
+ def respond_to?(method_id, include_private = false)
4
+ if match = DynamicFinderMatch.match(method_id)
5
+ return true if all_attributes_exists?(match.attribute_names)
6
+ elsif match = DynamicScopeMatch.match(method_id)
7
+ return true if all_attributes_exists?(match.attribute_names)
8
+ end
9
+
10
+ super
11
+ end
12
+
13
+ private
14
+
15
+ # Enables dynamic finders like <tt>User.find_by_user_name(user_name)</tt> and
16
+ # <tt>User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders
17
+ # section at the top of this file for more detailed information.
18
+ #
19
+ # It's even possible to use all the additional parameters to +find+. For example, the
20
+ # full interface for +find_all_by_amount+ is actually <tt>find_all_by_amount(amount, options)</tt>.
21
+ #
22
+ # Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
23
+ # is first invoked, so that future attempts to use it do not run through method_missing.
24
+ def method_missing(method_id, *arguments, &block)
25
+ if match = (DynamicFinderMatch.match(method_id) || DynamicScopeMatch.match(method_id))
26
+ attribute_names = match.attribute_names
27
+ super unless all_attributes_exists?(attribute_names)
28
+ if !(match.is_a?(DynamicFinderMatch) && match.instantiator? && arguments.first.is_a?(Hash)) && arguments.size < attribute_names.size
29
+ method_trace = "#{__FILE__}:#{__LINE__}:in `#{method_id}'"
30
+ backtrace = [method_trace] + caller
31
+ raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{attribute_names.size})", backtrace
32
+ end
33
+ if match.respond_to?(:scope?) && match.scope?
34
+ self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
35
+ def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
36
+ attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] # attributes = Hash[[:user_name, :password].zip(args)]
37
+ #
38
+ scoped(:conditions => attributes) # scoped(:conditions => attributes)
39
+ end # end
40
+ METHOD
41
+ send(method_id, *arguments)
42
+ elsif match.finder?
43
+ options = arguments.extract_options!
44
+ relation = options.any? ? scoped(options) : scoped
45
+ relation.send :find_by_attributes, match, attribute_names, *arguments, &block
46
+ elsif match.instantiator?
47
+ scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
48
+ end
49
+ else
50
+ super
51
+ end
52
+ end
53
+
54
+ # Similar in purpose to +expand_hash_conditions_for_aggregates+.
55
+ def expand_attribute_names_for_aggregates(attribute_names)
56
+ attribute_names.map { |attribute_name|
57
+ unless (aggregation = reflect_on_aggregation(attribute_name.to_sym)).nil?
58
+ aggregate_mapping(aggregation).map do |field_attr, _|
59
+ field_attr.to_sym
60
+ end
61
+ else
62
+ attribute_name.to_sym
63
+ end
64
+ }.flatten
65
+ end
66
+
67
+ def all_attributes_exists?(attribute_names)
68
+ (expand_attribute_names_for_aggregates(attribute_names) -
69
+ column_methods_hash.keys).empty?
70
+ end
71
+
72
+ def aggregate_mapping(reflection)
73
+ mapping = reflection.options[:mapping] || [reflection.name, reflection.name]
74
+ mapping.first.is_a?(Array) ? mapping : [mapping]
75
+ end
76
+
77
+
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+
3
+ # = Active Record Dynamic Scope Match
4
+ #
5
+ # Provides dynamic attribute-based scopes such as <tt>scoped_by_price(4.99)</tt>
6
+ # if, for example, the <tt>Product</tt> has an attribute with that name. You can
7
+ # chain more <tt>scoped_by_* </tt> methods after the other. It acts like a named
8
+ # scope except that it's dynamic.
9
+ class DynamicScopeMatch
10
+ def self.match(method)
11
+ return unless method.to_s =~ /^scoped_by_([_a-zA-Z]\w*)$/
12
+ new(true, $1 && $1.split('_and_'))
13
+ end
14
+
15
+ def initialize(scope, attribute_names)
16
+ @scope = scope
17
+ @attribute_names = attribute_names
18
+ end
19
+
20
+ attr_reader :scope, :attribute_names
21
+ alias :scope? :scope
22
+ end
23
+ end
@@ -0,0 +1,195 @@
1
+ module ActiveRecord
2
+
3
+ # = Active Record Errors
4
+ #
5
+ # Generic Active Record exception class.
6
+ class ActiveRecordError < StandardError
7
+ end
8
+
9
+ # Raised when the single-table inheritance mechanism fails to locate the subclass
10
+ # (for example due to improper usage of column that +inheritance_column+ points to).
11
+ class SubclassNotFound < ActiveRecordError #:nodoc:
12
+ end
13
+
14
+ # Raised when an object assigned to an association has an incorrect type.
15
+ #
16
+ # class Ticket < ActiveRecord::Base
17
+ # has_many :patches
18
+ # end
19
+ #
20
+ # class Patch < ActiveRecord::Base
21
+ # belongs_to :ticket
22
+ # end
23
+ #
24
+ # # Comments are not patches, this assignment raises AssociationTypeMismatch.
25
+ # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
26
+ class AssociationTypeMismatch < ActiveRecordError
27
+ end
28
+
29
+ # Raised when unserialized object's type mismatches one specified for serializable field.
30
+ class SerializationTypeMismatch < ActiveRecordError
31
+ end
32
+
33
+ # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt>
34
+ # misses adapter field).
35
+ class AdapterNotSpecified < ActiveRecordError
36
+ end
37
+
38
+ # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
39
+ class AdapterNotFound < ActiveRecordError
40
+ end
41
+
42
+ # Raised when connection to the database could not been established (for example when <tt>connection=</tt>
43
+ # is given a nil object).
44
+ class ConnectionNotEstablished < ActiveRecordError
45
+ end
46
+
47
+ # Raised when Active Record cannot find record by given id or set of ids.
48
+ class RecordNotFound < ActiveRecordError
49
+ end
50
+
51
+ # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
52
+ # saved because record is invalid.
53
+ class RecordNotSaved < ActiveRecordError
54
+ end
55
+
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
59
+ end
60
+
61
+ # Raised when SQL statement is invalid and the application gets a blank result.
62
+ class ThrowResult < ActiveRecordError
63
+ end
64
+
65
+ # Parent class for all specific exceptions which wrap database driver exceptions
66
+ # provides access to the original exception also.
67
+ class WrappedDatabaseException < StatementInvalid
68
+ attr_reader :original_exception
69
+
70
+ def initialize(message, original_exception)
71
+ super(message)
72
+ @original_exception = original_exception
73
+ end
74
+ end
75
+
76
+ # Raised when a record cannot be inserted because it would violate a uniqueness constraint.
77
+ class RecordNotUnique < WrappedDatabaseException
78
+ end
79
+
80
+ # Raised when a record cannot be inserted or updated because it references a non-existent record.
81
+ class InvalidForeignKey < WrappedDatabaseException
82
+ end
83
+
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
89
+ #
90
+ # Location.where("lat = ? AND lng = ?", 53.7362)
91
+ #
92
+ # two placeholders are given but only one variable to fill them.
93
+ class PreparedStatementInvalid < ActiveRecordError
94
+ end
95
+
96
+ # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
97
+ # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
98
+ # the page before the other.
99
+ #
100
+ # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
101
+ class StaleObjectError < ActiveRecordError
102
+ attr_reader :record, :attempted_action
103
+
104
+ def initialize(record, attempted_action)
105
+ @record = record
106
+ @attempted_action = attempted_action
107
+ end
108
+
109
+ def message
110
+ "Attempted to #{attempted_action} a stale object: #{record.class.name}"
111
+ end
112
+ end
113
+
114
+ # Raised when association is being configured improperly or
115
+ # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
116
+ class ConfigurationError < ActiveRecordError
117
+ end
118
+
119
+ # Raised on attempt to update record that is instantiated as read only.
120
+ class ReadOnlyRecord < ActiveRecordError
121
+ end
122
+
123
+ # ActiveRecord::Transactions::ClassMethods.transaction uses this exception
124
+ # to distinguish a deliberate rollback from other exceptional situations.
125
+ # Normally, raising an exception will cause the +transaction+ method to rollback
126
+ # the database transaction *and* pass on the exception. But if you raise an
127
+ # ActiveRecord::Rollback exception, then the database transaction will be rolled back,
128
+ # without passing on the exception.
129
+ #
130
+ # For example, you could do this in your controller to rollback a transaction:
131
+ #
132
+ # class BooksController < ActionController::Base
133
+ # def create
134
+ # Book.transaction do
135
+ # book = Book.new(params[:book])
136
+ # book.save!
137
+ # if today_is_friday?
138
+ # # The system must fail on Friday so that our support department
139
+ # # won't be out of job. We silently rollback this transaction
140
+ # # without telling the user.
141
+ # raise ActiveRecord::Rollback, "Call tech support!"
142
+ # end
143
+ # end
144
+ # # ActiveRecord::Rollback is the only exception that won't be passed on
145
+ # # by ActiveRecord::Base.transaction, so this line will still be reached
146
+ # # even on Friday.
147
+ # redirect_to root_url
148
+ # end
149
+ # end
150
+ class Rollback < ActiveRecordError
151
+ end
152
+
153
+ # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
154
+ class DangerousAttributeError < ActiveRecordError
155
+ end
156
+
157
+ # Raised when unknown attributes are supplied via mass assignment.
158
+ class UnknownAttributeError < NoMethodError
159
+ end
160
+
161
+ # Raised when an error occurred while doing a mass assignment to an attribute through the
162
+ # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
163
+ # offending attribute.
164
+ class AttributeAssignmentError < ActiveRecordError
165
+ attr_reader :exception, :attribute
166
+ def initialize(message, exception, attribute)
167
+ @exception = exception
168
+ @attribute = attribute
169
+ @message = message
170
+ end
171
+ end
172
+
173
+ # Raised when there are multiple errors while doing a mass assignment through the +attributes+
174
+ # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
175
+ # objects, each corresponding to the error while assigning to an attribute.
176
+ class MultiparameterAssignmentErrors < ActiveRecordError
177
+ attr_reader :errors
178
+ def initialize(errors)
179
+ @errors = errors
180
+ end
181
+ end
182
+
183
+ # Raised when a primary key is needed, but there is not one specified in the schema or model.
184
+ class UnknownPrimaryKey < ActiveRecordError
185
+ attr_reader :model
186
+
187
+ def initialize(model)
188
+ @model = model
189
+ end
190
+
191
+ def message
192
+ "Unknown primary key for table #{model.table_name} in model #{model}."
193
+ end
194
+ end
195
+ end