activerecord 4.2.0 → 5.2.8.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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,58 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
1
5
  module ActiveRecord
2
6
  module ModelSchema
3
7
  extend ActiveSupport::Concern
4
8
 
9
+ ##
10
+ # :singleton-method: primary_key_prefix_type
11
+ # :call-seq: primary_key_prefix_type
12
+ #
13
+ # The prefix type that will be prepended to every primary key column name.
14
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
15
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
16
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
17
+ # that this is a global setting for all Active Records.
18
+
19
+ ##
20
+ # :singleton-method: primary_key_prefix_type=
21
+ # :call-seq: primary_key_prefix_type=(prefix_type)
22
+ #
23
+ # Sets the prefix type that will be prepended to every primary key column name.
24
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
25
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
26
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
27
+ # that this is a global setting for all Active Records.
28
+
29
+ ##
30
+ # :singleton-method: table_name_prefix
31
+ # :call-seq: table_name_prefix
32
+ #
33
+ # The prefix string to prepend to every table name.
34
+
35
+ ##
36
+ # :singleton-method: table_name_prefix=
37
+ # :call-seq: table_name_prefix=(prefix)
38
+ #
39
+ # Sets the prefix string to prepend to every table name. So if set to "basecamp_", all table
40
+ # names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient
41
+ # way of creating a namespace for tables in a shared database. By default, the prefix is the
42
+ # empty string.
43
+ #
44
+ # If you are organising your models within modules you can add a prefix to the models within
45
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
46
+ # returns your chosen prefix.
47
+
48
+ ##
49
+ # :singleton-method: table_name_suffix
50
+ # :call-seq: table_name_suffix
51
+ #
52
+ # The suffix string to append to every table name.
53
+
54
+ ##
55
+ # :singleton-method: table_name_suffix=
56
+ # :call-seq: table_name_suffix=(suffix)
57
+ #
58
+ # Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
59
+ # "people_basecamp"). By default, the suffix is the empty string.
60
+ #
61
+ # If you are organising your models within modules, you can add a suffix to the models within
62
+ # a namespace by defining a singleton method in the parent module called table_name_suffix which
63
+ # returns your chosen suffix.
64
+
65
+ ##
66
+ # :singleton-method: schema_migrations_table_name
67
+ # :call-seq: schema_migrations_table_name
68
+ #
69
+ # The name of the schema migrations table. By default, the value is <tt>"schema_migrations"</tt>.
70
+
71
+ ##
72
+ # :singleton-method: schema_migrations_table_name=
73
+ # :call-seq: schema_migrations_table_name=(table_name)
74
+ #
75
+ # Sets the name of the schema migrations table.
76
+
77
+ ##
78
+ # :singleton-method: internal_metadata_table_name
79
+ # :call-seq: internal_metadata_table_name
80
+ #
81
+ # The name of the internal metadata table. By default, the value is <tt>"ar_internal_metadata"</tt>.
82
+
83
+ ##
84
+ # :singleton-method: internal_metadata_table_name=
85
+ # :call-seq: internal_metadata_table_name=(table_name)
86
+ #
87
+ # Sets the name of the internal metadata table.
88
+
89
+ ##
90
+ # :singleton-method: pluralize_table_names
91
+ # :call-seq: pluralize_table_names
92
+ #
93
+ # Indicates whether table names should be the pluralized versions of the corresponding class names.
94
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
95
+ # See table_name for the full rules on table/class naming. This is true, by default.
96
+
97
+ ##
98
+ # :singleton-method: pluralize_table_names=
99
+ # :call-seq: pluralize_table_names=(value)
100
+ #
101
+ # Set whether table names should be the pluralized versions of the corresponding class names.
102
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
103
+ # See table_name for the full rules on table/class naming. This is true, by default.
104
+
5
105
  included do
6
- ##
7
- # :singleton-method:
8
- # Accessor for the prefix type that will be prepended to every primary key column name.
9
- # The options are :table_name and :table_name_with_underscore. If the first is specified,
10
- # the Product class will look for "productid" instead of "id" as the primary column. If the
11
- # latter is specified, the Product class will look for "product_id" instead of "id". Remember
12
- # that this is a global setting for all Active Records.
13
106
  mattr_accessor :primary_key_prefix_type, instance_writer: false
14
107
 
15
- ##
16
- # :singleton-method:
17
- # Accessor for the name of the prefix string to prepend to every table name. So if set
18
- # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people",
19
- # etc. This is a convenient way of creating a namespace for tables in a shared database.
20
- # By default, the prefix is the empty string.
21
- #
22
- # If you are organising your models within modules you can add a prefix to the models within
23
- # a namespace by defining a singleton method in the parent module called table_name_prefix which
24
- # returns your chosen prefix.
25
- class_attribute :table_name_prefix, instance_writer: false
26
- self.table_name_prefix = ""
27
-
28
- ##
29
- # :singleton-method:
30
- # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
31
- # "people_basecamp"). By default, the suffix is the empty string.
32
- #
33
- # If you are organising your models within modules, you can add a suffix to the models within
34
- # a namespace by defining a singleton method in the parent module called table_name_suffix which
35
- # returns your chosen suffix.
36
- class_attribute :table_name_suffix, instance_writer: false
37
- self.table_name_suffix = ""
38
-
39
- ##
40
- # :singleton-method:
41
- # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
42
- class_attribute :schema_migrations_table_name, instance_accessor: false
43
- self.schema_migrations_table_name = "schema_migrations"
44
-
45
- ##
46
- # :singleton-method:
47
- # Indicates whether table names should be the pluralized versions of the corresponding class names.
48
- # If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
49
- # See table_name for the full rules on table/class naming. This is true, by default.
50
- class_attribute :pluralize_table_names, instance_writer: false
51
- self.pluralize_table_names = true
52
-
53
- self.inheritance_column = 'type'
108
+ class_attribute :table_name_prefix, instance_writer: false, default: ""
109
+ class_attribute :table_name_suffix, instance_writer: false, default: ""
110
+ class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
111
+ class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
112
+ class_attribute :pluralize_table_names, instance_writer: false, default: true
113
+
114
+ self.protected_environments = ["production"]
115
+ self.inheritance_column = "type"
116
+ self.ignored_columns = [].freeze
54
117
 
55
118
  delegate :type_for_attribute, to: :class
119
+
120
+ initialize_load_schema_monitor
56
121
  end
57
122
 
58
123
  # Derives the join table name for +first_table+ and +second_table+. The
@@ -111,17 +176,6 @@ module ActiveRecord
111
176
  # class Mouse < ActiveRecord::Base
112
177
  # self.table_name = "mice"
113
178
  # end
114
- #
115
- # Alternatively, you can override the table_name method to define your
116
- # own computation. (Possibly using <tt>super</tt> to manipulate the default
117
- # table name.) Example:
118
- #
119
- # class Post < ActiveRecord::Base
120
- # def self.table_name
121
- # "special_" + super
122
- # end
123
- # end
124
- # Post.table_name # => "special_posts"
125
179
  def table_name
126
180
  reset_table_name unless defined?(@table_name)
127
181
  @table_name
@@ -132,9 +186,6 @@ module ActiveRecord
132
186
  # class Project < ActiveRecord::Base
133
187
  # self.table_name = "project"
134
188
  # end
135
- #
136
- # You can also just define your own <tt>self.table_name</tt> method; see
137
- # the documentation for ActiveRecord::Base#table_name.
138
189
  def table_name=(value)
139
190
  value = value && value.to_s
140
191
 
@@ -147,7 +198,7 @@ module ActiveRecord
147
198
  @quoted_table_name = nil
148
199
  @arel_table = nil
149
200
  @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
150
- @relation = Relation.create(self, arel_table)
201
+ @predicate_builder = nil
151
202
  end
152
203
 
153
204
  # Returns a quoted version of the table name, used to construct SQL statements.
@@ -167,11 +218,26 @@ module ActiveRecord
167
218
  end
168
219
 
169
220
  def full_table_name_prefix #:nodoc:
170
- (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
221
+ (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
171
222
  end
172
223
 
173
224
  def full_table_name_suffix #:nodoc:
174
- (parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
225
+ (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
226
+ end
227
+
228
+ # The array of names of environments where destructive actions should be prohibited. By default,
229
+ # the value is <tt>["production"]</tt>.
230
+ def protected_environments
231
+ if defined?(@protected_environments)
232
+ @protected_environments
233
+ else
234
+ superclass.protected_environments
235
+ end
236
+ end
237
+
238
+ # Sets an array of names of environments where destructive actions should be prohibited.
239
+ def protected_environments=(environments)
240
+ @protected_environments = environments.map(&:to_s)
175
241
  end
176
242
 
177
243
  # Defines the name of the table column which will store the class name on single-table
@@ -193,6 +259,22 @@ module ActiveRecord
193
259
  @explicit_inheritance_column = true
194
260
  end
195
261
 
262
+ # The list of columns names the model should ignore. Ignored columns won't have attribute
263
+ # accessors defined, and won't be referenced in SQL queries.
264
+ def ignored_columns
265
+ if defined?(@ignored_columns)
266
+ @ignored_columns
267
+ else
268
+ superclass.ignored_columns
269
+ end
270
+ end
271
+
272
+ # Sets the columns names the model should ignore. Ignored columns won't have attribute
273
+ # accessors defined, and won't be referenced in SQL queries.
274
+ def ignored_columns=(columns)
275
+ @ignored_columns = columns.map(&:to_s)
276
+ end
277
+
196
278
  def sequence_name
197
279
  if base_class == self
198
280
  @sequence_name ||= reset_sequence_name
@@ -207,7 +289,7 @@ module ActiveRecord
207
289
  end
208
290
 
209
291
  # Sets the name of the sequence to use when generating ids to the given
210
- # value, or (if the value is nil or false) to the value returned by the
292
+ # value, or (if the value is +nil+ or +false+) to the value returned by the
211
293
  # given block. This is required for Oracle and is useful for any
212
294
  # database which relies on sequences for primary key generation.
213
295
  #
@@ -225,45 +307,96 @@ module ActiveRecord
225
307
  @explicit_sequence_name = true
226
308
  end
227
309
 
310
+ # Determines if the primary key values should be selected from their
311
+ # corresponding sequence before the insert statement.
312
+ def prefetch_primary_key?
313
+ connection.prefetch_primary_key?(table_name)
314
+ end
315
+
316
+ # Returns the next value that will be used as the primary key on
317
+ # an insert statement.
318
+ def next_sequence_value
319
+ connection.next_sequence_value(sequence_name)
320
+ end
321
+
228
322
  # Indicates whether the table associated with this class exists
229
323
  def table_exists?
230
- connection.schema_cache.table_exists?(table_name)
324
+ connection.schema_cache.data_source_exists?(table_name)
231
325
  end
232
326
 
233
327
  def attributes_builder # :nodoc:
234
- @attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
328
+ unless defined?(@attributes_builder) && @attributes_builder
329
+ defaults = _default_attributes.except(*(column_names - [primary_key]))
330
+ @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
331
+ end
332
+ @attributes_builder
235
333
  end
236
334
 
237
- def column_types # :nodoc:
238
- @column_types ||= columns_hash.transform_values(&:cast_type).tap do |h|
239
- h.default = Type::Value.new
240
- end
335
+ def columns_hash # :nodoc:
336
+ load_schema
337
+ @columns_hash
338
+ end
339
+
340
+ def columns
341
+ load_schema
342
+ @columns ||= columns_hash.values
343
+ end
344
+
345
+ def attribute_types # :nodoc:
346
+ load_schema
347
+ @attribute_types ||= Hash.new(Type.default_value)
241
348
  end
242
349
 
243
- def type_for_attribute(attr_name) # :nodoc:
244
- column_types[attr_name]
350
+ def yaml_encoder # :nodoc:
351
+ @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
352
+ end
353
+
354
+ # Returns the type of the attribute with the given name, after applying
355
+ # all modifiers. This method is the only valid source of information for
356
+ # anything related to the types of a model's attributes. This method will
357
+ # access the database and load the model's schema if it is required.
358
+ #
359
+ # The return value of this method will implement the interface described
360
+ # by ActiveModel::Type::Value (though the object itself may not subclass
361
+ # it).
362
+ #
363
+ # +attr_name+ The name of the attribute to retrieve the type for. Must be
364
+ # a string or a symbol.
365
+ def type_for_attribute(attr_name, &block)
366
+ attr_name = attr_name.to_s
367
+ if block
368
+ attribute_types.fetch(attr_name, &block)
369
+ else
370
+ attribute_types[attr_name]
371
+ end
245
372
  end
246
373
 
247
374
  # Returns a hash where the keys are column names and the values are
248
- # default values when instantiating the AR object for this table.
375
+ # default values when instantiating the Active Record object for this table.
249
376
  def column_defaults
250
- _default_attributes.to_hash
377
+ load_schema
378
+ @column_defaults ||= _default_attributes.deep_dup.to_hash
251
379
  end
252
380
 
253
381
  def _default_attributes # :nodoc:
254
- @default_attributes ||= attributes_builder.build_from_database(
255
- raw_default_values)
382
+ load_schema
383
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
256
384
  end
257
385
 
258
386
  # Returns an array of column names as strings.
259
387
  def column_names
260
- @column_names ||= columns.map { |column| column.name }
388
+ @column_names ||= columns.map(&:name)
261
389
  end
262
390
 
263
391
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
264
392
  # and columns used for single table inheritance have been removed.
265
393
  def content_columns
266
- @content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
394
+ @content_columns ||= columns.reject do |c|
395
+ c.name == primary_key ||
396
+ c.name == inheritance_column ||
397
+ c.name.end_with?("_id") ||
398
+ c.name.end_with?("_count")
399
+ end
267
400
  end
268
401
 
269
402
  # Resets all the cached information about columns, which will cause them
@@ -273,7 +406,7 @@ module ActiveRecord
273
406
  # when just after creating a table you want to populate it with some default
274
407
  # values, eg:
275
408
  #
276
- # class CreateJobLevels < ActiveRecord::Migration
409
+ # class CreateJobLevels < ActiveRecord::Migration[5.0]
277
410
  # def up
278
411
  # create_table :job_levels do |t|
279
412
  # t.integer :id
@@ -294,47 +427,95 @@ module ActiveRecord
294
427
  # end
295
428
  def reset_column_information
296
429
  connection.clear_cache!
297
- undefine_attribute_methods
298
- connection.schema_cache.clear_table_cache!(table_name) if table_exists?
299
-
300
- @arel_engine = nil
301
- @column_names = nil
302
- @column_types = nil
303
- @content_columns = nil
304
- @default_attributes = nil
305
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
306
- @relation = nil
430
+ ([self] + descendants).each(&:undefine_attribute_methods)
431
+ connection.schema_cache.clear_data_source_cache!(table_name)
432
+
433
+ reload_schema_from_cache
434
+ initialize_find_by_cache
307
435
  end
308
436
 
437
+ protected
438
+
439
+ def initialize_load_schema_monitor
440
+ @load_schema_monitor = Monitor.new
441
+ end
442
+
309
443
  private
310
444
 
311
- # Guesses the table name, but does not decorate it with prefix and suffix information.
312
- def undecorated_table_name(class_name = base_class.name)
313
- table_name = class_name.to_s.demodulize.underscore
314
- pluralize_table_names ? table_name.pluralize : table_name
315
- end
445
+ def inherited(child_class)
446
+ super
447
+ child_class.initialize_load_schema_monitor
448
+ end
316
449
 
317
- # Computes and returns a table name according to default conventions.
318
- def compute_table_name
319
- base = base_class
320
- if self == base
321
- # Nested classes are prefixed with singular parent table name.
322
- if parent < Base && !parent.abstract_class?
323
- contained = parent.table_name
324
- contained = contained.singularize if parent.pluralize_table_names
325
- contained += '_'
450
+ def schema_loaded?
451
+ defined?(@schema_loaded) && @schema_loaded
452
+ end
453
+
454
+ def load_schema
455
+ return if schema_loaded?
456
+ @load_schema_monitor.synchronize do
457
+ return if defined?(@columns_hash) && @columns_hash
458
+
459
+ load_schema!
460
+
461
+ @schema_loaded = true
326
462
  end
463
+ end
327
464
 
328
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
329
- else
330
- # STI subclasses always use their superclass' table.
331
- base.table_name
465
+ def load_schema!
466
+ @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
467
+ @columns_hash.each do |name, column|
468
+ define_attribute(
469
+ name,
470
+ connection.lookup_cast_type_from_column(column),
471
+ default: column.default,
472
+ user_provided_default: false
473
+ )
474
+ end
332
475
  end
333
- end
334
476
 
335
- def raw_default_values
336
- columns_hash.transform_values(&:default)
337
- end
477
+ def reload_schema_from_cache
478
+ @arel_table = nil
479
+ @column_names = nil
480
+ @attribute_types = nil
481
+ @content_columns = nil
482
+ @default_attributes = nil
483
+ @column_defaults = nil
484
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
485
+ @attributes_builder = nil
486
+ @columns = nil
487
+ @columns_hash = nil
488
+ @schema_loaded = false
489
+ @attribute_names = nil
490
+ @yaml_encoder = nil
491
+ direct_descendants.each do |descendant|
492
+ descendant.send(:reload_schema_from_cache)
493
+ end
494
+ end
495
+
496
+ # Guesses the table name, but does not decorate it with prefix and suffix information.
497
+ def undecorated_table_name(class_name = base_class.name)
498
+ table_name = class_name.to_s.demodulize.underscore
499
+ pluralize_table_names ? table_name.pluralize : table_name
500
+ end
501
+
502
+ # Computes and returns a table name according to default conventions.
503
+ def compute_table_name
504
+ base = base_class
505
+ if self == base
506
+ # Nested classes are prefixed with singular parent table name.
507
+ if parent < Base && !parent.abstract_class?
508
+ contained = parent.table_name
509
+ contained = contained.singularize if parent.pluralize_table_names
510
+ contained += "_"
511
+ end
512
+
513
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
514
+ else
515
+ # STI subclasses always use their superclass' table.
516
+ base.table_name
517
+ end
518
+ end
338
519
  end
339
520
  end
340
521
  end