activerecord 4.2.11.3 → 5.0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (246) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1281 -1204
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record/aggregations.rb +35 -24
  8. data/lib/active_record/association_relation.rb +3 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +11 -9
  11. data/lib/active_record/associations/association_scope.rb +73 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +49 -41
  21. data/lib/active_record/associations/collection_proxy.rb +67 -27
  22. data/lib/active_record/associations/foreign_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_association.rb +20 -71
  24. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  25. data/lib/active_record/associations/has_one_association.rb +12 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  27. data/lib/active_record/associations/join_dependency.rb +29 -19
  28. data/lib/active_record/associations/preloader/association.rb +46 -52
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +14 -4
  34. data/lib/active_record/associations/singular_association.rb +7 -1
  35. data/lib/active_record/associations/through_association.rb +11 -3
  36. data/lib/active_record/associations.rb +317 -209
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute_assignment.rb +19 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  48. data/lib/active_record/attribute_methods/write.rb +13 -37
  49. data/lib/active_record/attribute_methods.rb +76 -47
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +6 -4
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attributes.rb +199 -81
  54. data/lib/active_record/autosave_association.rb +49 -16
  55. data/lib/active_record/base.rb +32 -23
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  100. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  105. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  106. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  107. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  108. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  110. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  111. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  112. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  113. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  114. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  115. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  117. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
  118. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  119. data/lib/active_record/connection_handling.rb +37 -14
  120. data/lib/active_record/core.rb +89 -107
  121. data/lib/active_record/counter_cache.rb +13 -24
  122. data/lib/active_record/dynamic_matchers.rb +1 -20
  123. data/lib/active_record/enum.rb +113 -76
  124. data/lib/active_record/errors.rb +87 -48
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +1 -1
  127. data/lib/active_record/fixture_set/file.rb +26 -5
  128. data/lib/active_record/fixtures.rb +76 -40
  129. data/lib/active_record/gem_version.rb +4 -4
  130. data/lib/active_record/inheritance.rb +32 -40
  131. data/lib/active_record/integration.rb +4 -4
  132. data/lib/active_record/internal_metadata.rb +56 -0
  133. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  134. data/lib/active_record/locale/en.yml +3 -2
  135. data/lib/active_record/locking/optimistic.rb +15 -15
  136. data/lib/active_record/locking/pessimistic.rb +1 -1
  137. data/lib/active_record/log_subscriber.rb +43 -21
  138. data/lib/active_record/migration/command_recorder.rb +59 -18
  139. data/lib/active_record/migration/compatibility.rb +126 -0
  140. data/lib/active_record/migration.rb +363 -133
  141. data/lib/active_record/model_schema.rb +129 -41
  142. data/lib/active_record/nested_attributes.rb +58 -29
  143. data/lib/active_record/null_relation.rb +16 -8
  144. data/lib/active_record/persistence.rb +121 -80
  145. data/lib/active_record/query_cache.rb +15 -18
  146. data/lib/active_record/querying.rb +10 -9
  147. data/lib/active_record/railtie.rb +23 -16
  148. data/lib/active_record/railties/controller_runtime.rb +1 -1
  149. data/lib/active_record/railties/databases.rake +69 -46
  150. data/lib/active_record/readonly_attributes.rb +1 -1
  151. data/lib/active_record/reflection.rb +282 -115
  152. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  153. data/lib/active_record/relation/batches.rb +139 -34
  154. data/lib/active_record/relation/calculations.rb +79 -108
  155. data/lib/active_record/relation/delegation.rb +7 -20
  156. data/lib/active_record/relation/finder_methods.rb +163 -81
  157. data/lib/active_record/relation/from_clause.rb +32 -0
  158. data/lib/active_record/relation/merger.rb +16 -42
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  160. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  163. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  166. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  167. data/lib/active_record/relation/predicate_builder.rb +120 -107
  168. data/lib/active_record/relation/query_attribute.rb +19 -0
  169. data/lib/active_record/relation/query_methods.rb +308 -244
  170. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  171. data/lib/active_record/relation/spawn_methods.rb +4 -7
  172. data/lib/active_record/relation/where_clause.rb +174 -0
  173. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  174. data/lib/active_record/relation.rb +176 -116
  175. data/lib/active_record/result.rb +4 -3
  176. data/lib/active_record/runtime_registry.rb +1 -1
  177. data/lib/active_record/sanitization.rb +95 -66
  178. data/lib/active_record/schema.rb +26 -22
  179. data/lib/active_record/schema_dumper.rb +62 -38
  180. data/lib/active_record/schema_migration.rb +11 -14
  181. data/lib/active_record/scoping/default.rb +23 -9
  182. data/lib/active_record/scoping/named.rb +49 -28
  183. data/lib/active_record/scoping.rb +32 -15
  184. data/lib/active_record/secure_token.rb +38 -0
  185. data/lib/active_record/serialization.rb +2 -4
  186. data/lib/active_record/statement_cache.rb +16 -14
  187. data/lib/active_record/store.rb +8 -3
  188. data/lib/active_record/suppressor.rb +58 -0
  189. data/lib/active_record/table_metadata.rb +68 -0
  190. data/lib/active_record/tasks/database_tasks.rb +57 -43
  191. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  192. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  193. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  194. data/lib/active_record/timestamp.rb +20 -9
  195. data/lib/active_record/touch_later.rb +58 -0
  196. data/lib/active_record/transactions.rb +138 -56
  197. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  198. data/lib/active_record/type/date.rb +2 -45
  199. data/lib/active_record/type/date_time.rb +2 -49
  200. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  201. data/lib/active_record/type/internal/timezone.rb +15 -0
  202. data/lib/active_record/type/serialized.rb +15 -14
  203. data/lib/active_record/type/time.rb +10 -16
  204. data/lib/active_record/type/type_map.rb +4 -4
  205. data/lib/active_record/type.rb +66 -17
  206. data/lib/active_record/type_caster/connection.rb +29 -0
  207. data/lib/active_record/type_caster/map.rb +19 -0
  208. data/lib/active_record/type_caster.rb +7 -0
  209. data/lib/active_record/validations/absence.rb +23 -0
  210. data/lib/active_record/validations/associated.rb +10 -3
  211. data/lib/active_record/validations/length.rb +24 -0
  212. data/lib/active_record/validations/presence.rb +11 -12
  213. data/lib/active_record/validations/uniqueness.rb +30 -29
  214. data/lib/active_record/validations.rb +33 -32
  215. data/lib/active_record.rb +8 -4
  216. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  217. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  218. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  219. data/lib/rails/generators/active_record/migration.rb +7 -0
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +60 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -64
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. data/lib/active_record/type/value.rb +0 -110
@@ -31,6 +31,12 @@ module ActiveRecord
31
31
  # Conversation.active
32
32
  # Conversation.archived
33
33
  #
34
+ # Of course, you can also query them directly if the scopes don't fit your
35
+ # needs:
36
+ #
37
+ # Conversation.where(status: [:active, :archived])
38
+ # Conversation.where.not(status: :active)
39
+ #
34
40
  # You can set the default value from the database declaration, like:
35
41
  #
36
42
  # create_table :conversations do |t|
@@ -40,13 +46,13 @@ module ActiveRecord
40
46
  # Good practice is to let the first declared status be the default.
41
47
  #
42
48
  # Finally, it's also possible to explicitly map the relation between attribute and
43
- # database integer with a +Hash+:
49
+ # database integer with a hash:
44
50
  #
45
51
  # class Conversation < ActiveRecord::Base
46
52
  # enum status: { active: 0, archived: 1 }
47
53
  # end
48
54
  #
49
- # Note that when an +Array+ is used, the implicit mapping from the values to database
55
+ # Note that when an array is used, the implicit mapping from the values to database
50
56
  # integers is derived from the order the values appear in the array. In the example,
51
57
  # <tt>:active</tt> is mapped to +0+ as it's the first element, and <tt>:archived</tt>
52
58
  # is mapped to +1+. In general, the +i+-th element is mapped to <tt>i-1</tt> in the
@@ -54,19 +60,39 @@ module ActiveRecord
54
60
  #
55
61
  # Therefore, once a value is added to the enum array, its position in the array must
56
62
  # be maintained, and new values should only be added to the end of the array. To
57
- # remove unused values, the explicit +Hash+ syntax should be used.
63
+ # remove unused values, the explicit hash syntax should be used.
58
64
  #
59
65
  # In rare circumstances you might need to access the mapping directly.
60
66
  # The mappings are exposed through a class method with the pluralized attribute
61
- # name:
67
+ # name, which return the mapping in a +HashWithIndifferentAccess+:
62
68
  #
63
- # Conversation.statuses # => { "active" => 0, "archived" => 1 }
69
+ # Conversation.statuses[:active] # => 0
70
+ # Conversation.statuses["archived"] # => 1
64
71
  #
65
- # Use that class method when you need to know the ordinal value of an enum:
72
+ # Use that class method when you need to know the ordinal value of an enum.
73
+ # For example, you can use that when manually building SQL strings:
66
74
  #
67
75
  # Conversation.where("status <> ?", Conversation.statuses[:archived])
68
76
  #
69
- # Where conditions on an enum attribute must use the ordinal value of an enum.
77
+ # You can use the +:_prefix+ or +:_suffix+ options when you need to define
78
+ # multiple enums with same values. If the passed value is +true+, the methods
79
+ # are prefixed/suffixed with the name of the enum. It is also possible to
80
+ # supply a custom value:
81
+ #
82
+ # class Conversation < ActiveRecord::Base
83
+ # enum status: [:active, :archived], _suffix: true
84
+ # enum comments_status: [:active, :inactive], _prefix: :comments
85
+ # end
86
+ #
87
+ # With the above example, the bang and predicate methods along with the
88
+ # associated scopes are now prefixed and/or suffixed accordingly:
89
+ #
90
+ # conversation.active_status!
91
+ # conversation.archived_status? # => false
92
+ #
93
+ # conversation.comments_inactive!
94
+ # conversation.comments_active? # => false
95
+
70
96
  module Enum
71
97
  def self.extended(base) # :nodoc:
72
98
  base.class_attribute(:defined_enums, instance_writer: false)
@@ -78,56 +104,93 @@ module ActiveRecord
78
104
  super
79
105
  end
80
106
 
107
+ class EnumType < Type::Value # :nodoc:
108
+ def initialize(name, mapping, subtype)
109
+ @name = name
110
+ @mapping = mapping
111
+ @subtype = subtype
112
+ end
113
+
114
+ def cast(value)
115
+ return if value.blank?
116
+
117
+ if mapping.has_key?(value)
118
+ value.to_s
119
+ elsif mapping.has_value?(value)
120
+ mapping.key(value)
121
+ else
122
+ assert_valid_value(value)
123
+ end
124
+ end
125
+
126
+ def deserialize(value)
127
+ return if value.nil?
128
+ mapping.key(subtype.deserialize(value))
129
+ end
130
+
131
+ def serialize(value)
132
+ mapping.fetch(value, value)
133
+ end
134
+
135
+ def assert_valid_value(value)
136
+ unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
137
+ raise ArgumentError, "'#{value}' is not a valid #{name}"
138
+ end
139
+ end
140
+
141
+ protected
142
+
143
+ attr_reader :name, :mapping, :subtype
144
+ end
145
+
81
146
  def enum(definitions)
82
147
  klass = self
148
+ enum_prefix = definitions.delete(:_prefix)
149
+ enum_suffix = definitions.delete(:_suffix)
83
150
  definitions.each do |name, values|
84
151
  # statuses = { }
85
152
  enum_values = ActiveSupport::HashWithIndifferentAccess.new
86
153
  name = name.to_sym
87
154
 
88
- # def self.statuses statuses end
155
+ # def self.statuses() statuses end
89
156
  detect_enum_conflict!(name, name.to_s.pluralize, true)
90
157
  klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values }
91
158
 
92
- _enum_methods_module.module_eval do
93
- # def status=(value) self[:status] = statuses[value] end
94
- klass.send(:detect_enum_conflict!, name, "#{name}=")
95
- define_method("#{name}=") { |value|
96
- if enum_values.has_key?(value) || value.blank?
97
- self[name] = enum_values[value]
98
- elsif enum_values.has_value?(value)
99
- # Assigning a value directly is not a end-user feature, hence it's not documented.
100
- # This is used internally to make building objects from the generated scopes work
101
- # as expected, i.e. +Conversation.archived.build.archived?+ should be true.
102
- self[name] = value
103
- else
104
- raise ArgumentError, "'#{value}' is not a valid #{name}"
105
- end
106
- }
107
-
108
- # def status() statuses.key self[:status] end
109
- klass.send(:detect_enum_conflict!, name, name)
110
- define_method(name) { enum_values.key self[name] }
159
+ detect_enum_conflict!(name, name)
160
+ detect_enum_conflict!(name, "#{name}=")
111
161
 
112
- # def status_before_type_cast() statuses.key self[:status] end
113
- klass.send(:detect_enum_conflict!, name, "#{name}_before_type_cast")
114
- define_method("#{name}_before_type_cast") { enum_values.key self[name] }
162
+ decorate_attribute_type(name, :enum) do |subtype|
163
+ EnumType.new(name, enum_values, subtype)
164
+ end
115
165
 
166
+ _enum_methods_module.module_eval do
116
167
  pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
117
168
  pairs.each do |value, i|
169
+ if enum_prefix == true
170
+ prefix = "#{name}_"
171
+ elsif enum_prefix
172
+ prefix = "#{enum_prefix}_"
173
+ end
174
+ if enum_suffix == true
175
+ suffix = "_#{name}"
176
+ elsif enum_suffix
177
+ suffix = "_#{enum_suffix}"
178
+ end
179
+
180
+ value_method_name = "#{prefix}#{value}#{suffix}"
118
181
  enum_values[value] = i
119
182
 
120
183
  # def active?() status == 0 end
121
- klass.send(:detect_enum_conflict!, name, "#{value}?")
122
- define_method("#{value}?") { self[name] == i }
184
+ klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
185
+ define_method("#{value_method_name}?") { self[name] == value.to_s }
123
186
 
124
187
  # def active!() update! status: :active end
125
- klass.send(:detect_enum_conflict!, name, "#{value}!")
126
- define_method("#{value}!") { update! name => value }
188
+ klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
189
+ define_method("#{value_method_name}!") { update! name => value }
127
190
 
128
191
  # scope :active, -> { where status: 0 }
129
- klass.send(:detect_enum_conflict!, name, value, true)
130
- klass.scope value, -> { klass.where name => i }
192
+ klass.send(:detect_enum_conflict!, name, value_method_name, true)
193
+ klass.scope value_method_name, -> { where(name => value) }
131
194
  end
132
195
  end
133
196
  defined_enums[name.to_s] = enum_values
@@ -137,25 +200,7 @@ module ActiveRecord
137
200
  private
138
201
  def _enum_methods_module
139
202
  @_enum_methods_module ||= begin
140
- mod = Module.new do
141
- private
142
- def save_changed_attribute(attr_name, old)
143
- if (mapping = self.class.defined_enums[attr_name.to_s])
144
- value = _read_attribute(attr_name)
145
- if attribute_changed?(attr_name)
146
- if mapping[old] == value
147
- clear_attribute_changes([attr_name])
148
- end
149
- else
150
- if old != value
151
- set_attribute_was(attr_name, mapping.key(old))
152
- end
153
- end
154
- else
155
- super
156
- end
157
- end
158
- end
203
+ mod = Module.new
159
204
  include mod
160
205
  mod
161
206
  end
@@ -168,30 +213,22 @@ module ActiveRecord
168
213
 
169
214
  def detect_enum_conflict!(enum_name, method_name, klass_method = false)
170
215
  if klass_method && dangerous_class_method?(method_name)
171
- raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
172
- enum: enum_name,
173
- klass: self.name,
174
- type: 'class',
175
- method: method_name,
176
- source: 'Active Record'
177
- }
216
+ raise_conflict_error(enum_name, method_name, type: 'class')
178
217
  elsif !klass_method && dangerous_attribute_method?(method_name)
179
- raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
180
- enum: enum_name,
181
- klass: self.name,
182
- type: 'instance',
183
- method: method_name,
184
- source: 'Active Record'
185
- }
218
+ raise_conflict_error(enum_name, method_name)
186
219
  elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
187
- raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
188
- enum: enum_name,
189
- klass: self.name,
190
- type: 'instance',
191
- method: method_name,
192
- source: 'another enum'
193
- }
220
+ raise_conflict_error(enum_name, method_name, source: 'another enum')
194
221
  end
195
222
  end
223
+
224
+ def raise_conflict_error(enum_name, method_name, type: 'instance', source: 'Active Record')
225
+ raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
226
+ enum: enum_name,
227
+ klass: self.name,
228
+ type: type,
229
+ method: method_name,
230
+ source: source
231
+ }
232
+ end
196
233
  end
197
234
  end
@@ -7,8 +7,10 @@ module ActiveRecord
7
7
  end
8
8
 
9
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:
10
+ # (for example due to improper usage of column that
11
+ # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
12
+ # points to).
13
+ class SubclassNotFound < ActiveRecordError
12
14
  end
13
15
 
14
16
  # Raised when an object assigned to an association has an incorrect type.
@@ -40,27 +42,40 @@ module ActiveRecord
40
42
  class AdapterNotFound < ActiveRecordError
41
43
  end
42
44
 
43
- # Raised when connection to the database could not been established (for
44
- # example when +connection=+ is given a nil object).
45
+ # Raised when connection to the database could not been established (for example when
46
+ # {ActiveRecord::Base.connection=}[rdoc-ref:ConnectionHandling#connection]
47
+ # is given a nil object).
45
48
  class ConnectionNotEstablished < ActiveRecordError
46
49
  end
47
50
 
48
- # Raised when Active Record cannot find record by given id or set of ids.
51
+ # Raised when Active Record cannot find a record by given id or set of ids.
49
52
  class RecordNotFound < ActiveRecordError
53
+ attr_reader :model, :primary_key, :id
54
+
55
+ def initialize(message = nil, model = nil, primary_key = nil, id = nil)
56
+ @primary_key = primary_key
57
+ @model = model
58
+ @id = id
59
+
60
+ super(message)
61
+ end
50
62
  end
51
63
 
52
- # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
53
- # saved because record is invalid.
64
+ # Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
65
+ # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
66
+ # methods when a record is invalid and can not be saved.
54
67
  class RecordNotSaved < ActiveRecordError
55
68
  attr_reader :record
56
69
 
57
- def initialize(message, record = nil)
70
+ def initialize(message = nil, record = nil)
58
71
  @record = record
59
72
  super(message)
60
73
  end
61
74
  end
62
75
 
63
- # Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
76
+ # Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
77
+ # when a call to {#destroy}[rdoc-ref:Persistence#destroy!]
78
+ # would return false.
64
79
  #
65
80
  # begin
66
81
  # complex_operation_that_internally_calls_destroy!
@@ -71,7 +86,7 @@ module ActiveRecord
71
86
  class RecordNotDestroyed < ActiveRecordError
72
87
  attr_reader :record
73
88
 
74
- def initialize(message, record = nil)
89
+ def initialize(message = nil, record = nil)
75
90
  @record = record
76
91
  super(message)
77
92
  end
@@ -79,18 +94,26 @@ module ActiveRecord
79
94
 
80
95
  # Superclass for all database execution errors.
81
96
  #
82
- # Wraps the underlying database error as +original_exception+.
97
+ # Wraps the underlying database error as +cause+.
83
98
  class StatementInvalid < ActiveRecordError
84
- attr_reader :original_exception
85
99
 
86
- def initialize(message, original_exception = nil)
87
- super(message)
88
- @original_exception = original_exception
100
+ def initialize(message = nil, original_exception = nil)
101
+ if original_exception
102
+ ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
103
+ "Exceptions will automatically capture the original exception.", caller)
104
+ end
105
+
106
+ super(message || $!.try(:message))
107
+ end
108
+
109
+ def original_exception
110
+ ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
111
+ cause
89
112
  end
90
113
  end
91
114
 
92
115
  # Defunct wrapper class kept for compatibility.
93
- # +StatementInvalid+ wraps the original exception now.
116
+ # StatementInvalid wraps the original exception now.
94
117
  class WrappedDatabaseException < StatementInvalid
95
118
  end
96
119
 
@@ -102,9 +125,13 @@ module ActiveRecord
102
125
  class InvalidForeignKey < WrappedDatabaseException
103
126
  end
104
127
 
128
+ # Raised when a record cannot be inserted or updated because a value too long for a column type.
129
+ class ValueTooLong < StatementInvalid
130
+ end
131
+
105
132
  # 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.
133
+ # (for example, when using {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method)
134
+ # does not match number of expected values supplied.
108
135
  #
109
136
  # For example, when there are two placeholders with only one value supplied:
110
137
  #
@@ -116,6 +143,11 @@ module ActiveRecord
116
143
  class NoDatabaseError < StatementInvalid
117
144
  end
118
145
 
146
+ # Raised when Postgres returns 'cached plan must not change result type' and
147
+ # we cannot retry gracefully (e.g. inside a transaction)
148
+ class PreparedStatementCacheExpired < StatementInvalid
149
+ end
150
+
119
151
  # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
120
152
  # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
121
153
  # the page before the other.
@@ -125,16 +157,22 @@ module ActiveRecord
125
157
  class StaleObjectError < ActiveRecordError
126
158
  attr_reader :record, :attempted_action
127
159
 
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
160
+ def initialize(record = nil, attempted_action = nil)
161
+ if record && attempted_action
162
+ @record = record
163
+ @attempted_action = attempted_action
164
+ super("Attempted to #{attempted_action} a stale object: #{record.class.name}.")
165
+ else
166
+ super("Stale object error.")
167
+ end
132
168
  end
133
169
 
134
170
  end
135
171
 
136
172
  # 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+
173
+ # offset and limit together with
174
+ # {ActiveRecord::Base.has_many}[rdoc-ref:Associations::ClassMethods#has_many] or
175
+ # {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many]
138
176
  # associations.
139
177
  class ConfigurationError < ActiveRecordError
140
178
  end
@@ -143,9 +181,10 @@ module ActiveRecord
143
181
  class ReadOnlyRecord < ActiveRecordError
144
182
  end
145
183
 
146
- # ActiveRecord::Transactions::ClassMethods.transaction uses this exception
147
- # to distinguish a deliberate rollback from other exceptional situations.
148
- # Normally, raising an exception will cause the +transaction+ method to rollback
184
+ # {ActiveRecord::Base.transaction}[rdoc-ref:Transactions::ClassMethods#transaction]
185
+ # uses this exception to distinguish a deliberate rollback from other exceptional situations.
186
+ # Normally, raising an exception will cause the
187
+ # {.transaction}[rdoc-ref:Transactions::ClassMethods#transaction] method to rollback
149
188
  # the database transaction *and* pass on the exception. But if you raise an
150
189
  # ActiveRecord::Rollback exception, then the database transaction will be rolled back,
151
190
  # without passing on the exception.
@@ -179,38 +218,29 @@ module ActiveRecord
179
218
  end
180
219
 
181
220
  # Raised when unknown attributes are supplied via mass assignment.
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
-
192
- end
221
+ UnknownAttributeError = ActiveModel::UnknownAttributeError
193
222
 
194
223
  # Raised when an error occurred while doing a mass assignment to an attribute through the
195
- # +attributes=+ method. The exception has an +attribute+ property that is the name of the
196
- # offending attribute.
224
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
225
+ # The exception has an +attribute+ property that is the name of the offending attribute.
197
226
  class AttributeAssignmentError < ActiveRecordError
198
227
  attr_reader :exception, :attribute
199
228
 
200
- def initialize(message, exception, attribute)
229
+ def initialize(message = nil, exception = nil, attribute = nil)
201
230
  super(message)
202
231
  @exception = exception
203
232
  @attribute = attribute
204
233
  end
205
234
  end
206
235
 
207
- # Raised when there are multiple errors while doing a mass assignment through the +attributes+
236
+ # Raised when there are multiple errors while doing a mass assignment through the
237
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=]
208
238
  # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
209
239
  # objects, each corresponding to the error while assigning to an attribute.
210
240
  class MultiparameterAssignmentErrors < ActiveRecordError
211
241
  attr_reader :errors
212
242
 
213
- def initialize(errors)
243
+ def initialize(errors = nil)
214
244
  @errors = errors
215
245
  end
216
246
  end
@@ -219,11 +249,15 @@ module ActiveRecord
219
249
  class UnknownPrimaryKey < ActiveRecordError
220
250
  attr_reader :model
221
251
 
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)
226
- @model = model
252
+ def initialize(model = nil, description = nil)
253
+ if model
254
+ message = "Unknown primary key for table #{model.table_name} in model #{model}."
255
+ message += "\n#{description}" if description
256
+ @model = model
257
+ super(message)
258
+ else
259
+ super("Unknown primary key.")
260
+ end
227
261
  end
228
262
  end
229
263
 
@@ -247,7 +281,12 @@ module ActiveRecord
247
281
  # * You are joining an existing open transaction
248
282
  # * You are creating a nested (savepoint) transaction
249
283
  #
250
- # The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
284
+ # The mysql2 and postgresql adapters support setting the transaction isolation level.
251
285
  class TransactionIsolationError < ActiveRecordError
252
286
  end
287
+
288
+ # IrreversibleOrderError is raised when a relation's order is too complex for
289
+ # +reverse_order+ to automatically reverse.
290
+ class IrreversibleOrderError < ActiveRecordError
291
+ end
253
292
  end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  #
8
8
  # returns the collected queries local to the current thread.
9
9
  #
10
- # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
10
+ # See the documentation of ActiveSupport::PerThreadRegistry
11
11
  # for further details.
12
12
  class ExplainRegistry # :nodoc:
13
13
  extend ActiveSupport::PerThreadRegistry
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  end
15
15
 
16
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.
17
+ # our own EXPLAINs no matter how loopingly beautiful that would be.
18
18
  #
19
19
  # On the other hand, we want to monitor the performance of our real database
20
20
  # queries, not the performance of the access to the query cache.
@@ -17,29 +17,50 @@ module ActiveRecord
17
17
 
18
18
  def initialize(file)
19
19
  @file = file
20
- @rows = nil
21
20
  end
22
21
 
23
22
  def each(&block)
24
23
  rows.each(&block)
25
24
  end
26
25
 
26
+ def model_class
27
+ config_row['model_class']
28
+ end
27
29
 
28
30
  private
29
31
  def rows
30
- return @rows if @rows
32
+ @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == '_fixture' }
33
+ end
31
34
 
32
- begin
35
+ def config_row
36
+ @config_row ||= begin
37
+ row = raw_rows.find { |fixture_name, _| fixture_name == '_fixture' }
38
+ if row
39
+ row.last
40
+ else
41
+ {'model_class': nil}
42
+ end
43
+ end
44
+ end
45
+
46
+ def raw_rows
47
+ @raw_rows ||= begin
33
48
  data = YAML.load(render(IO.read(@file)))
49
+ data ? validate(data).to_a : []
34
50
  rescue ArgumentError, Psych::SyntaxError => error
35
51
  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
52
  end
37
- @rows = data ? validate(data).to_a : []
53
+ end
54
+
55
+ def prepare_erb(content)
56
+ erb = ERB.new(content)
57
+ erb.filename = @file
58
+ erb
38
59
  end
39
60
 
40
61
  def render(content)
41
62
  context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
42
- ERB.new(content).result(context.get_binding)
63
+ prepare_erb(content).result(context.get_binding)
43
64
  end
44
65
 
45
66
  # Validate our unmarshalled data.