activerecord 5.2.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +937 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +217 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +188 -0
  8. data/lib/active_record/aggregations.rb +283 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1860 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +299 -0
  13. data/lib/active_record/associations/association_scope.rb +168 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +130 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +140 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +163 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +82 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +135 -0
  20. data/lib/active_record/associations/builder/has_many.rb +17 -0
  21. data/lib/active_record/associations/builder/has_one.rb +30 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +42 -0
  23. data/lib/active_record/associations/collection_association.rb +513 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1131 -0
  25. data/lib/active_record/associations/foreign_association.rb +13 -0
  26. data/lib/active_record/associations/has_many_association.rb +144 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +227 -0
  28. data/lib/active_record/associations/has_one_association.rb +120 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +262 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +60 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +193 -0
  35. data/lib/active_record/associations/preloader/association.rb +131 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +107 -0
  37. data/lib/active_record/associations/singular_association.rb +73 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +88 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +492 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +78 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +150 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +143 -0
  45. data/lib/active_record/attribute_methods/query.rb +42 -0
  46. data/lib/active_record/attribute_methods/read.rb +85 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +68 -0
  50. data/lib/active_record/attributes.rb +266 -0
  51. data/lib/active_record/autosave_association.rb +498 -0
  52. data/lib/active_record/base.rb +329 -0
  53. data/lib/active_record/callbacks.rb +353 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/collection_cache_key.rb +53 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1068 -0
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +72 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +540 -0
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +145 -0
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +200 -0
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +685 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1396 -0
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +628 -0
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +887 -0
  70. data/lib/active_record/connection_adapters/column.rb +91 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  73. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +863 -0
  118. data/lib/active_record/connection_adapters/schema_cache.rb +118 -0
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +573 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +145 -0
  129. data/lib/active_record/core.rb +559 -0
  130. data/lib/active_record/counter_cache.rb +218 -0
  131. data/lib/active_record/define_callbacks.rb +22 -0
  132. data/lib/active_record/dynamic_matchers.rb +122 -0
  133. data/lib/active_record/enum.rb +244 -0
  134. data/lib/active_record/errors.rb +380 -0
  135. data/lib/active_record/explain.rb +50 -0
  136. data/lib/active_record/explain_registry.rb +32 -0
  137. data/lib/active_record/explain_subscriber.rb +34 -0
  138. data/lib/active_record/fixture_set/file.rb +82 -0
  139. data/lib/active_record/fixtures.rb +1065 -0
  140. data/lib/active_record/gem_version.rb +17 -0
  141. data/lib/active_record/inheritance.rb +283 -0
  142. data/lib/active_record/integration.rb +155 -0
  143. data/lib/active_record/internal_metadata.rb +45 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  145. data/lib/active_record/locale/en.yml +48 -0
  146. data/lib/active_record/locking/optimistic.rb +198 -0
  147. data/lib/active_record/locking/pessimistic.rb +89 -0
  148. data/lib/active_record/log_subscriber.rb +137 -0
  149. data/lib/active_record/migration.rb +1378 -0
  150. data/lib/active_record/migration/command_recorder.rb +240 -0
  151. data/lib/active_record/migration/compatibility.rb +217 -0
  152. data/lib/active_record/migration/join_table.rb +17 -0
  153. data/lib/active_record/model_schema.rb +521 -0
  154. data/lib/active_record/nested_attributes.rb +600 -0
  155. data/lib/active_record/no_touching.rb +58 -0
  156. data/lib/active_record/null_relation.rb +68 -0
  157. data/lib/active_record/persistence.rb +763 -0
  158. data/lib/active_record/query_cache.rb +45 -0
  159. data/lib/active_record/querying.rb +70 -0
  160. data/lib/active_record/railtie.rb +226 -0
  161. data/lib/active_record/railties/console_sandbox.rb +7 -0
  162. data/lib/active_record/railties/controller_runtime.rb +56 -0
  163. data/lib/active_record/railties/databases.rake +377 -0
  164. data/lib/active_record/readonly_attributes.rb +24 -0
  165. data/lib/active_record/reflection.rb +1044 -0
  166. data/lib/active_record/relation.rb +629 -0
  167. data/lib/active_record/relation/batches.rb +287 -0
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  169. data/lib/active_record/relation/calculations.rb +417 -0
  170. data/lib/active_record/relation/delegation.rb +147 -0
  171. data/lib/active_record/relation/finder_methods.rb +565 -0
  172. data/lib/active_record/relation/from_clause.rb +26 -0
  173. data/lib/active_record/relation/merger.rb +193 -0
  174. data/lib/active_record/relation/predicate_builder.rb +152 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  182. data/lib/active_record/relation/query_attribute.rb +45 -0
  183. data/lib/active_record/relation/query_methods.rb +1231 -0
  184. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  185. data/lib/active_record/relation/spawn_methods.rb +77 -0
  186. data/lib/active_record/relation/where_clause.rb +186 -0
  187. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  188. data/lib/active_record/result.rb +149 -0
  189. data/lib/active_record/runtime_registry.rb +24 -0
  190. data/lib/active_record/sanitization.rb +222 -0
  191. data/lib/active_record/schema.rb +70 -0
  192. data/lib/active_record/schema_dumper.rb +255 -0
  193. data/lib/active_record/schema_migration.rb +56 -0
  194. data/lib/active_record/scoping.rb +106 -0
  195. data/lib/active_record/scoping/default.rb +152 -0
  196. data/lib/active_record/scoping/named.rb +213 -0
  197. data/lib/active_record/secure_token.rb +40 -0
  198. data/lib/active_record/serialization.rb +22 -0
  199. data/lib/active_record/statement_cache.rb +121 -0
  200. data/lib/active_record/store.rb +211 -0
  201. data/lib/active_record/suppressor.rb +61 -0
  202. data/lib/active_record/table_metadata.rb +82 -0
  203. data/lib/active_record/tasks/database_tasks.rb +337 -0
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  207. data/lib/active_record/timestamp.rb +153 -0
  208. data/lib/active_record/touch_later.rb +64 -0
  209. data/lib/active_record/transactions.rb +502 -0
  210. data/lib/active_record/translation.rb +24 -0
  211. data/lib/active_record/type.rb +79 -0
  212. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  213. data/lib/active_record/type/date.rb +9 -0
  214. data/lib/active_record/type/date_time.rb +9 -0
  215. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  217. data/lib/active_record/type/internal/timezone.rb +17 -0
  218. data/lib/active_record/type/json.rb +30 -0
  219. data/lib/active_record/type/serialized.rb +71 -0
  220. data/lib/active_record/type/text.rb +11 -0
  221. data/lib/active_record/type/time.rb +21 -0
  222. data/lib/active_record/type/type_map.rb +62 -0
  223. data/lib/active_record/type/unsigned_integer.rb +17 -0
  224. data/lib/active_record/type_caster.rb +9 -0
  225. data/lib/active_record/type_caster/connection.rb +33 -0
  226. data/lib/active_record/type_caster/map.rb +23 -0
  227. data/lib/active_record/validations.rb +93 -0
  228. data/lib/active_record/validations/absence.rb +25 -0
  229. data/lib/active_record/validations/associated.rb +60 -0
  230. data/lib/active_record/validations/length.rb +26 -0
  231. data/lib/active_record/validations/presence.rb +68 -0
  232. data/lib/active_record/validations/uniqueness.rb +238 -0
  233. data/lib/active_record/version.rb +10 -0
  234. data/lib/rails/generators/active_record.rb +19 -0
  235. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  236. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  237. data/lib/rails/generators/active_record/migration.rb +35 -0
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +78 -0
  239. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  240. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  241. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  242. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  243. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  244. metadata +333 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Migration
5
+ module JoinTable #:nodoc:
6
+ private
7
+
8
+ def find_join_table_name(table_1, table_2, options = {})
9
+ options.delete(:table_name) || join_table_name(table_1, table_2)
10
+ end
11
+
12
+ def join_table_name(table_1, table_2)
13
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,521 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveRecord
6
+ module ModelSchema
7
+ extend ActiveSupport::Concern
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
+
105
+ included do
106
+ mattr_accessor :primary_key_prefix_type, instance_writer: false
107
+
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
117
+
118
+ delegate :type_for_attribute, to: :class
119
+
120
+ initialize_load_schema_monitor
121
+ end
122
+
123
+ # Derives the join table name for +first_table+ and +second_table+. The
124
+ # table names appear in alphabetical order. A common prefix is removed
125
+ # (useful for namespaced models like Music::Artist and Music::Record):
126
+ #
127
+ # artists, records => artists_records
128
+ # records, artists => artists_records
129
+ # music_artists, music_records => music_artists_records
130
+ def self.derive_join_table_name(first_table, second_table) # :nodoc:
131
+ [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
132
+ end
133
+
134
+ module ClassMethods
135
+ # Guesses the table name (in forced lower-case) based on the name of the class in the
136
+ # inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
137
+ # looks like: Reply < Message < ActiveRecord::Base, then Message is used
138
+ # to guess the table name even when called on Reply. The rules used to do the guess
139
+ # are handled by the Inflector class in Active Support, which knows almost all common
140
+ # English inflections. You can add new inflections in config/initializers/inflections.rb.
141
+ #
142
+ # Nested classes are given table names prefixed by the singular form of
143
+ # the parent's table name. Enclosing modules are not considered.
144
+ #
145
+ # ==== Examples
146
+ #
147
+ # class Invoice < ActiveRecord::Base
148
+ # end
149
+ #
150
+ # file class table_name
151
+ # invoice.rb Invoice invoices
152
+ #
153
+ # class Invoice < ActiveRecord::Base
154
+ # class Lineitem < ActiveRecord::Base
155
+ # end
156
+ # end
157
+ #
158
+ # file class table_name
159
+ # invoice.rb Invoice::Lineitem invoice_lineitems
160
+ #
161
+ # module Invoice
162
+ # class Lineitem < ActiveRecord::Base
163
+ # end
164
+ # end
165
+ #
166
+ # file class table_name
167
+ # invoice/lineitem.rb Invoice::Lineitem lineitems
168
+ #
169
+ # Additionally, the class-level +table_name_prefix+ is prepended and the
170
+ # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
171
+ # the table name guess for an Invoice class becomes "myapp_invoices".
172
+ # Invoice::Lineitem becomes "myapp_invoice_lineitems".
173
+ #
174
+ # You can also set your own table name explicitly:
175
+ #
176
+ # class Mouse < ActiveRecord::Base
177
+ # self.table_name = "mice"
178
+ # end
179
+ def table_name
180
+ reset_table_name unless defined?(@table_name)
181
+ @table_name
182
+ end
183
+
184
+ # Sets the table name explicitly. Example:
185
+ #
186
+ # class Project < ActiveRecord::Base
187
+ # self.table_name = "project"
188
+ # end
189
+ def table_name=(value)
190
+ value = value && value.to_s
191
+
192
+ if defined?(@table_name)
193
+ return if value == @table_name
194
+ reset_column_information if connected?
195
+ end
196
+
197
+ @table_name = value
198
+ @quoted_table_name = nil
199
+ @arel_table = nil
200
+ @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
201
+ @predicate_builder = nil
202
+ end
203
+
204
+ # Returns a quoted version of the table name, used to construct SQL statements.
205
+ def quoted_table_name
206
+ @quoted_table_name ||= connection.quote_table_name(table_name)
207
+ end
208
+
209
+ # Computes the table name, (re)sets it internally, and returns it.
210
+ def reset_table_name #:nodoc:
211
+ self.table_name = if abstract_class?
212
+ superclass == Base ? nil : superclass.table_name
213
+ elsif superclass.abstract_class?
214
+ superclass.table_name || compute_table_name
215
+ else
216
+ compute_table_name
217
+ end
218
+ end
219
+
220
+ def full_table_name_prefix #:nodoc:
221
+ (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
222
+ end
223
+
224
+ def full_table_name_suffix #:nodoc:
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)
241
+ end
242
+
243
+ # Defines the name of the table column which will store the class name on single-table
244
+ # inheritance situations.
245
+ #
246
+ # The default inheritance column name is +type+, which means it's a
247
+ # reserved word inside Active Record. To be able to use single-table
248
+ # inheritance with another column name, or to use the column +type+ in
249
+ # your own model for something else, you can set +inheritance_column+:
250
+ #
251
+ # self.inheritance_column = 'zoink'
252
+ def inheritance_column
253
+ (@inheritance_column ||= nil) || superclass.inheritance_column
254
+ end
255
+
256
+ # Sets the value of inheritance_column
257
+ def inheritance_column=(value)
258
+ @inheritance_column = value.to_s
259
+ @explicit_inheritance_column = true
260
+ end
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
+
278
+ def sequence_name
279
+ if base_class == self
280
+ @sequence_name ||= reset_sequence_name
281
+ else
282
+ (@sequence_name ||= nil) || base_class.sequence_name
283
+ end
284
+ end
285
+
286
+ def reset_sequence_name #:nodoc:
287
+ @explicit_sequence_name = false
288
+ @sequence_name = connection.default_sequence_name(table_name, primary_key)
289
+ end
290
+
291
+ # Sets the name of the sequence to use when generating ids to the given
292
+ # value, or (if the value is +nil+ or +false+) to the value returned by the
293
+ # given block. This is required for Oracle and is useful for any
294
+ # database which relies on sequences for primary key generation.
295
+ #
296
+ # If a sequence name is not explicitly set when using Oracle,
297
+ # it will default to the commonly used pattern of: #{table_name}_seq
298
+ #
299
+ # If a sequence name is not explicitly set when using PostgreSQL, it
300
+ # will discover the sequence corresponding to your primary key for you.
301
+ #
302
+ # class Project < ActiveRecord::Base
303
+ # self.sequence_name = "projectseq" # default would have been "project_seq"
304
+ # end
305
+ def sequence_name=(value)
306
+ @sequence_name = value.to_s
307
+ @explicit_sequence_name = true
308
+ end
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
+
322
+ # Indicates whether the table associated with this class exists
323
+ def table_exists?
324
+ connection.schema_cache.data_source_exists?(table_name)
325
+ end
326
+
327
+ def attributes_builder # :nodoc:
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
333
+ end
334
+
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)
348
+ end
349
+
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
372
+ end
373
+
374
+ # Returns a hash where the keys are column names and the values are
375
+ # default values when instantiating the Active Record object for this table.
376
+ def column_defaults
377
+ load_schema
378
+ @column_defaults ||= _default_attributes.deep_dup.to_hash
379
+ end
380
+
381
+ def _default_attributes # :nodoc:
382
+ load_schema
383
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
384
+ end
385
+
386
+ # Returns an array of column names as strings.
387
+ def column_names
388
+ @column_names ||= columns.map(&:name)
389
+ end
390
+
391
+ # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
392
+ # and columns used for single table inheritance have been removed.
393
+ def content_columns
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
400
+ end
401
+
402
+ # Resets all the cached information about columns, which will cause them
403
+ # to be reloaded on the next request.
404
+ #
405
+ # The most common usage pattern for this method is probably in a migration,
406
+ # when just after creating a table you want to populate it with some default
407
+ # values, eg:
408
+ #
409
+ # class CreateJobLevels < ActiveRecord::Migration[5.0]
410
+ # def up
411
+ # create_table :job_levels do |t|
412
+ # t.integer :id
413
+ # t.string :name
414
+ #
415
+ # t.timestamps
416
+ # end
417
+ #
418
+ # JobLevel.reset_column_information
419
+ # %w{assistant executive manager director}.each do |type|
420
+ # JobLevel.create(name: type)
421
+ # end
422
+ # end
423
+ #
424
+ # def down
425
+ # drop_table :job_levels
426
+ # end
427
+ # end
428
+ def reset_column_information
429
+ connection.clear_cache!
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
435
+ end
436
+
437
+ protected
438
+
439
+ def initialize_load_schema_monitor
440
+ @load_schema_monitor = Monitor.new
441
+ end
442
+
443
+ private
444
+
445
+ def inherited(child_class)
446
+ super
447
+ child_class.initialize_load_schema_monitor
448
+ end
449
+
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
462
+ end
463
+ end
464
+
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
475
+ end
476
+
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
519
+ end
520
+ end
521
+ end