activerecord 3.2.19 → 5.0.0

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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  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 +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,7 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Date < ActiveModel::Type::Date
4
+ include Internal::Timezone
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class DateTime < ActiveModel::Type::DateTime
4
+ include Internal::Timezone
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class HashLookupTypeMap < TypeMap # :nodoc:
4
+ def alias_type(type, alias_type)
5
+ register_type(type) { |_, *args| lookup(alias_type, *args) }
6
+ end
7
+
8
+ def key?(key)
9
+ @mapping.key?(key)
10
+ end
11
+
12
+ def keys
13
+ @mapping.keys
14
+ end
15
+
16
+ private
17
+
18
+ def perform_fetch(type, *args, &block)
19
+ @mapping.fetch(type, block).call(type, *args)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module Internal # :nodoc:
4
+ class AbstractJson < ActiveModel::Type::Value # :nodoc:
5
+ include ActiveModel::Type::Helpers::Mutable
6
+
7
+ def type
8
+ :json
9
+ end
10
+
11
+ def deserialize(value)
12
+ if value.is_a?(::String)
13
+ ::ActiveSupport::JSON.decode(value) rescue nil
14
+ else
15
+ value
16
+ end
17
+ end
18
+
19
+ def serialize(value)
20
+ ::ActiveSupport::JSON.encode(value)
21
+ end
22
+
23
+ def accessor
24
+ ActiveRecord::Store::StringKeyedHashAccessor
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module Internal
4
+ module Timezone
5
+ def is_utc?
6
+ ActiveRecord::Base.default_timezone == :utc
7
+ end
8
+
9
+ def default_timezone
10
+ ActiveRecord::Base.default_timezone
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,63 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Serialized < DelegateClass(ActiveModel::Type::Value) # :nodoc:
4
+ include ActiveModel::Type::Helpers::Mutable
5
+
6
+ attr_reader :subtype, :coder
7
+
8
+ def initialize(subtype, coder)
9
+ @subtype = subtype
10
+ @coder = coder
11
+ super(subtype)
12
+ end
13
+
14
+ def deserialize(value)
15
+ if default_value?(value)
16
+ value
17
+ else
18
+ coder.load(super)
19
+ end
20
+ end
21
+
22
+ def serialize(value)
23
+ return if value.nil?
24
+ unless default_value?(value)
25
+ super coder.dump(value)
26
+ end
27
+ end
28
+
29
+ def inspect
30
+ Kernel.instance_method(:inspect).bind(self).call
31
+ end
32
+
33
+ def changed_in_place?(raw_old_value, value)
34
+ return false if value.nil?
35
+ raw_new_value = encoded(value)
36
+ raw_old_value.nil? != raw_new_value.nil? ||
37
+ subtype.changed_in_place?(raw_old_value, raw_new_value)
38
+ end
39
+
40
+ def accessor
41
+ ActiveRecord::Store::IndifferentHashAccessor
42
+ end
43
+
44
+ def assert_valid_value(value)
45
+ if coder.respond_to?(:assert_valid_value)
46
+ coder.assert_valid_value(value)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def default_value?(value)
53
+ value == coder.load(nil)
54
+ end
55
+
56
+ def encoded(value)
57
+ unless default_value?(value)
58
+ coder.dump(value)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Time < ActiveModel::Type::Time
4
+ include Internal::Timezone
5
+
6
+ class Value < DelegateClass(::Time) # :nodoc:
7
+ end
8
+
9
+ def serialize(value)
10
+ case value = super
11
+ when ::Time
12
+ Value.new(value)
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,64 @@
1
+ require 'concurrent/map'
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ class TypeMap # :nodoc:
6
+ def initialize
7
+ @mapping = {}
8
+ @cache = Concurrent::Map.new do |h, key|
9
+ h.fetch_or_store(key, Concurrent::Map.new)
10
+ end
11
+ end
12
+
13
+ def lookup(lookup_key, *args)
14
+ fetch(lookup_key, *args) { default_value }
15
+ end
16
+
17
+ def fetch(lookup_key, *args, &block)
18
+ @cache[lookup_key].fetch_or_store(args) do
19
+ perform_fetch(lookup_key, *args, &block)
20
+ end
21
+ end
22
+
23
+ def register_type(key, value = nil, &block)
24
+ raise ::ArgumentError unless value || block
25
+ @cache.clear
26
+
27
+ if block
28
+ @mapping[key] = block
29
+ else
30
+ @mapping[key] = proc { value }
31
+ end
32
+ end
33
+
34
+ def alias_type(key, target_key)
35
+ register_type(key) do |sql_type, *args|
36
+ metadata = sql_type[/\(.*\)/, 0]
37
+ lookup("#{target_key}#{metadata}", *args)
38
+ end
39
+ end
40
+
41
+ def clear
42
+ @mapping.clear
43
+ end
44
+
45
+ private
46
+
47
+ def perform_fetch(lookup_key, *args)
48
+ matching_pair = @mapping.reverse_each.detect do |key, _|
49
+ key === lookup_key
50
+ end
51
+
52
+ if matching_pair
53
+ matching_pair.last.call(lookup_key, *args)
54
+ else
55
+ yield lookup_key, *args
56
+ end
57
+ end
58
+
59
+ def default_value
60
+ @default_value ||= ActiveModel::Type::Value.new
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,72 @@
1
+ require 'active_model/type'
2
+
3
+ require 'active_record/type/internal/abstract_json'
4
+ require 'active_record/type/internal/timezone'
5
+
6
+ require 'active_record/type/date'
7
+ require 'active_record/type/date_time'
8
+ require 'active_record/type/time'
9
+
10
+ require 'active_record/type/serialized'
11
+ require 'active_record/type/adapter_specific_registry'
12
+
13
+ require 'active_record/type/type_map'
14
+ require 'active_record/type/hash_lookup_type_map'
15
+
16
+ module ActiveRecord
17
+ module Type
18
+ @registry = AdapterSpecificRegistry.new
19
+
20
+ class << self
21
+ attr_accessor :registry # :nodoc:
22
+ delegate :add_modifier, to: :registry
23
+
24
+ # Add a new type to the registry, allowing it to be referenced as a
25
+ # symbol by {ActiveRecord::Base.attribute}[rdoc-ref:Attributes::ClassMethods#attribute].
26
+ # If your type is only meant to be used with a specific database adapter, you can
27
+ # do so by passing <tt>adapter: :postgresql</tt>. If your type has the same
28
+ # name as a native type for the current adapter, an exception will be
29
+ # raised unless you specify an +:override+ option. <tt>override: true</tt> will
30
+ # cause your type to be used instead of the native type. <tt>override:
31
+ # false</tt> will cause the native type to be used over yours if one exists.
32
+ def register(type_name, klass = nil, **options, &block)
33
+ registry.register(type_name, klass, **options, &block)
34
+ end
35
+
36
+ def lookup(*args, adapter: current_adapter_name, **kwargs) # :nodoc:
37
+ registry.lookup(*args, adapter: adapter, **kwargs)
38
+ end
39
+
40
+ private
41
+
42
+ def current_adapter_name
43
+ ActiveRecord::Base.connection.adapter_name.downcase.to_sym
44
+ end
45
+ end
46
+
47
+ Helpers = ActiveModel::Type::Helpers
48
+ BigInteger = ActiveModel::Type::BigInteger
49
+ Binary = ActiveModel::Type::Binary
50
+ Boolean = ActiveModel::Type::Boolean
51
+ Decimal = ActiveModel::Type::Decimal
52
+ DecimalWithoutScale = ActiveModel::Type::DecimalWithoutScale
53
+ Float = ActiveModel::Type::Float
54
+ Integer = ActiveModel::Type::Integer
55
+ String = ActiveModel::Type::String
56
+ Text = ActiveModel::Type::Text
57
+ UnsignedInteger = ActiveModel::Type::UnsignedInteger
58
+ Value = ActiveModel::Type::Value
59
+
60
+ register(:big_integer, Type::BigInteger, override: false)
61
+ register(:binary, Type::Binary, override: false)
62
+ register(:boolean, Type::Boolean, override: false)
63
+ register(:date, Type::Date, override: false)
64
+ register(:datetime, Type::DateTime, override: false)
65
+ register(:decimal, Type::Decimal, override: false)
66
+ register(:float, Type::Float, override: false)
67
+ register(:integer, Type::Integer, override: false)
68
+ register(:string, Type::String, override: false)
69
+ register(:text, Type::Text, override: false)
70
+ register(:time, Type::Time, override: false)
71
+ end
72
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveRecord
2
+ module TypeCaster
3
+ class Connection # :nodoc:
4
+ def initialize(klass, table_name)
5
+ @klass = klass
6
+ @table_name = table_name
7
+ end
8
+
9
+ def type_cast_for_database(attribute_name, value)
10
+ return value if value.is_a?(Arel::Nodes::BindParam)
11
+ column = column_for(attribute_name)
12
+ connection.type_cast_from_column(column, value)
13
+ end
14
+
15
+ protected
16
+
17
+ attr_reader :table_name
18
+ delegate :connection, to: :@klass
19
+
20
+ private
21
+
22
+ def column_for(attribute_name)
23
+ if connection.schema_cache.data_source_exists?(table_name)
24
+ connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveRecord
2
+ module TypeCaster
3
+ class Map # :nodoc:
4
+ def initialize(types)
5
+ @types = types
6
+ end
7
+
8
+ def type_cast_for_database(attr_name, value)
9
+ return value if value.is_a?(Arel::Nodes::BindParam)
10
+ type = types.type_for_attribute(attr_name.to_s)
11
+ type.serialize(value)
12
+ end
13
+
14
+ protected
15
+
16
+ attr_reader :types
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_record/type_caster/map'
2
+ require 'active_record/type_caster/connection'
3
+
4
+ module ActiveRecord
5
+ module TypeCaster # :nodoc:
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module Validations
3
+ class AbsenceValidator < ActiveModel::Validations::AbsenceValidator # :nodoc:
4
+ def validate_each(record, attribute, association_or_value)
5
+ if record.class._reflect_on_association(attribute)
6
+ association_or_value = Array.wrap(association_or_value).reject(&:marked_for_destruction?)
7
+ end
8
+ super
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # Validates that the specified attributes are not present (as defined by
14
+ # Object#present?). If the attribute is an association, the associated object
15
+ # is considered absent if it was marked for destruction.
16
+ #
17
+ # See ActiveModel::Validations::HelperMethods.validates_absence_of for more information.
18
+ def validates_absence_of(*attr_names)
19
+ validates_with AbsenceValidator, _merge_attributes(attr_names)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,15 +1,22 @@
1
1
  module ActiveRecord
2
2
  module Validations
3
- class AssociatedValidator < ActiveModel::EachValidator
3
+ class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
4
4
  def validate_each(record, attribute, value)
5
- if Array.wrap(value).reject {|r| r.marked_for_destruction? || r.valid?}.any?
6
- record.errors.add(attribute, :invalid, options.merge(:value => value))
5
+ if Array(value).reject { |r| valid_object?(r) }.any?
6
+ record.errors.add(attribute, :invalid, options.merge(value: value))
7
7
  end
8
8
  end
9
+
10
+ private
11
+
12
+ def valid_object?(record)
13
+ (record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?
14
+ end
9
15
  end
10
16
 
11
17
  module ClassMethods
12
- # Validates whether the associated object or objects are all valid themselves. Works with any kind of association.
18
+ # Validates whether the associated object or objects are all valid.
19
+ # Works with any kind of association.
13
20
  #
14
21
  # class Book < ActiveRecord::Base
15
22
  # has_many :pages
@@ -18,23 +25,31 @@ module ActiveRecord
18
25
  # validates_associated :pages, :library
19
26
  # end
20
27
  #
21
- # WARNING: This validation must not be used on both ends of an association. Doing so will lead to a circular dependency and cause infinite recursion.
28
+ # WARNING: This validation must not be used on both ends of an association.
29
+ # Doing so will lead to a circular dependency and cause infinite recursion.
22
30
  #
23
- # NOTE: This validation will not fail if the association hasn't been assigned. If you want to
24
- # ensure that the association is both present and guaranteed to be valid, you also need to
25
- # use +validates_presence_of+.
31
+ # NOTE: This validation will not fail if the association hasn't been
32
+ # assigned. If you want to ensure that the association is both present and
33
+ # guaranteed to be valid, you also need to use
34
+ # {validates_presence_of}[rdoc-ref:Validations::ClassMethods#validates_presence_of].
26
35
  #
27
36
  # Configuration options:
28
- # * <tt>:message</tt> - A custom error message (default is: "is invalid")
29
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
30
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
31
- # and <tt>:update</tt>.
32
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
33
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
34
- # method, proc or string should return or evaluate to a true or false value.
35
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
36
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
37
- # method, proc or string should return or evaluate to a true or false value.
37
+ #
38
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid").
39
+ # * <tt>:on</tt> - Specifies the contexts where this validation is active.
40
+ # Runs in all validation contexts by default (nil). You can pass a symbol
41
+ # or an array of symbols. (e.g. <tt>on: :create</tt> or
42
+ # <tt>on: :custom_validation_context</tt> or
43
+ # <tt>on: [:create, :custom_validation_context]</tt>)
44
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
45
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
46
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
47
+ # proc or string should return or evaluate to a +true+ or +false+ value.
48
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to
49
+ # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
50
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
51
+ # method, proc or string should return or evaluate to a +true+ or +false+
52
+ # value.
38
53
  def validates_associated(*attr_names)
39
54
  validates_with AssociatedValidator, _merge_attributes(attr_names)
40
55
  end
@@ -0,0 +1,24 @@
1
+ module ActiveRecord
2
+ module Validations
3
+ class LengthValidator < ActiveModel::Validations::LengthValidator # :nodoc:
4
+ def validate_each(record, attribute, association_or_value)
5
+ if association_or_value.respond_to?(:loaded?) && association_or_value.loaded?
6
+ association_or_value = association_or_value.target.reject(&:marked_for_destruction?)
7
+ end
8
+ super
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # Validates that the specified attributes match the length restrictions supplied.
14
+ # If the attribute is an association, records that are marked for destruction are not counted.
15
+ #
16
+ # See ActiveModel::Validations::HelperMethods.validates_length_of for more information.
17
+ def validates_length_of(*attr_names)
18
+ validates_with LengthValidator, _merge_attributes(attr_names)
19
+ end
20
+
21
+ alias_method :validates_size_of, :validates_length_of
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,66 @@
1
+ module ActiveRecord
2
+ module Validations
3
+ class PresenceValidator < ActiveModel::Validations::PresenceValidator # :nodoc:
4
+ def validate_each(record, attribute, association_or_value)
5
+ if record.class._reflect_on_association(attribute)
6
+ association_or_value = Array.wrap(association_or_value).reject(&:marked_for_destruction?)
7
+ end
8
+ super
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # Validates that the specified attributes are not blank (as defined by
14
+ # Object#blank?), and, if the attribute is an association, that the
15
+ # associated object is not marked for destruction. Happens by default
16
+ # on save.
17
+ #
18
+ # class Person < ActiveRecord::Base
19
+ # has_one :face
20
+ # validates_presence_of :face
21
+ # end
22
+ #
23
+ # The face attribute must be in the object and it cannot be blank or marked
24
+ # for destruction.
25
+ #
26
+ # If you want to validate the presence of a boolean field (where the real values
27
+ # are true and false), you will want to use
28
+ # <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
29
+ #
30
+ # This is due to the way Object#blank? handles boolean values:
31
+ # <tt>false.blank? # => true</tt>.
32
+ #
33
+ # This validator defers to the Active Model validation for presence, adding the
34
+ # check to see that an associated object is not marked for destruction. This
35
+ # prevents the parent object from validating successfully and saving, which then
36
+ # deletes the associated object, thus putting the parent object into an invalid
37
+ # state.
38
+ #
39
+ # NOTE: This validation will not fail while using it with an association
40
+ # if the latter was assigned but not valid. If you want to ensure that
41
+ # it is both present and valid, you also need to use
42
+ # {validates_associated}[rdoc-ref:Validations::ClassMethods#validates_associated].
43
+ #
44
+ # Configuration options:
45
+ # * <tt>:message</tt> - A custom error message (default is: "can't be blank").
46
+ # * <tt>:on</tt> - Specifies the contexts where this validation is active.
47
+ # Runs in all validation contexts by default (nil). You can pass a symbol
48
+ # or an array of symbols. (e.g. <tt>on: :create</tt> or
49
+ # <tt>on: :custom_validation_context</tt> or
50
+ # <tt>on: [:create, :custom_validation_context]</tt>)
51
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
52
+ # the validation should occur (e.g. <tt>if: :allow_validation</tt>, or
53
+ # <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
54
+ # or string should return or evaluate to a +true+ or +false+ value.
55
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
56
+ # if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
57
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
58
+ # proc or string should return or evaluate to a +true+ or +false+ value.
59
+ # * <tt>:strict</tt> - Specifies whether validation should be strict.
60
+ # See ActiveModel::Validation#validates! for more information.
61
+ def validates_presence_of(*attr_names)
62
+ validates_with PresenceValidator, _merge_attributes(attr_names)
63
+ end
64
+ end
65
+ end
66
+ end