activerecord 4.2.11.3 → 5.0.7.2

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -5,15 +5,36 @@ module ActiveRecord
5
5
  # knows how to invert the following commands:
6
6
  #
7
7
  # * add_column
8
+ # * add_foreign_key
8
9
  # * add_index
10
+ # * add_reference
9
11
  # * add_timestamps
10
- # * create_table
12
+ # * change_column
13
+ # * change_column_default (must supply a :from and :to option)
14
+ # * change_column_null
11
15
  # * create_join_table
16
+ # * create_table
17
+ # * disable_extension
18
+ # * drop_join_table
19
+ # * drop_table (must supply a block)
20
+ # * enable_extension
21
+ # * remove_column (must supply a type)
22
+ # * remove_columns (must specify at least one column name or more)
23
+ # * remove_foreign_key (must supply a second table)
24
+ # * remove_index
25
+ # * remove_reference
12
26
  # * remove_timestamps
13
27
  # * rename_column
14
28
  # * rename_index
15
29
  # * rename_table
16
30
  class CommandRecorder
31
+ ReversibleAndIrreversibleMethods = [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
32
+ :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
33
+ :change_column_default, :add_reference, :remove_reference, :transaction,
34
+ :drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
35
+ :change_column, :execute, :remove_columns, :change_column_null,
36
+ :add_foreign_key, :remove_foreign_key
37
+ ]
17
38
  include JoinTable
18
39
 
19
40
  attr_accessor :commands, :delegate, :reverting
@@ -41,7 +62,7 @@ module ActiveRecord
41
62
  @reverting = !@reverting
42
63
  end
43
64
 
44
- # record +command+. +command+ should be a method name and arguments.
65
+ # Record +command+. +command+ should be a method name and arguments.
45
66
  # For example:
46
67
  #
47
68
  # recorder.record(:method_name, [:arg1, :arg2])
@@ -62,7 +83,12 @@ module ActiveRecord
62
83
  # invert the +command+.
63
84
  def inverse_of(command, args, &block)
64
85
  method = :"invert_#{command}"
65
- raise IrreversibleMigration unless respond_to?(method, true)
86
+ raise IrreversibleMigration, <<-MSG.strip_heredoc unless respond_to?(method, true)
87
+ This migration uses #{command}, which is not automatically reversible.
88
+ To make the migration reversible you can either:
89
+ 1. Define #up and #down methods in place of the #change method.
90
+ 2. Use the #reversible method to define reversible behavior.
91
+ MSG
66
92
  send(method, args, &block)
67
93
  end
68
94
 
@@ -70,14 +96,7 @@ module ActiveRecord
70
96
  super || delegate.respond_to?(*args)
71
97
  end
72
98
 
73
- [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
74
- :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
75
- :change_column_default, :add_reference, :remove_reference, :transaction,
76
- :drop_join_table, :drop_table, :execute_block, :enable_extension,
77
- :change_column, :execute, :remove_columns, :change_column_null,
78
- :add_foreign_key, :remove_foreign_key
79
- # irreversible methods need to be here too
80
- ].each do |method|
99
+ ReversibleAndIrreversibleMethods.each do |method|
81
100
  class_eval <<-EOV, __FILE__, __LINE__ + 1
82
101
  def #{method}(*args, &block) # def create_table(*args, &block)
83
102
  record(:"#{method}", args, &block) # record(:create_table, args, &block)
@@ -151,19 +170,31 @@ module ActiveRecord
151
170
  end
152
171
 
153
172
  def invert_remove_index(args)
154
- table, options = *args
155
-
156
- unless options && options.is_a?(Hash) && options[:column]
157
- raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
173
+ table, options_or_column = *args
174
+ if (options = options_or_column).is_a?(Hash)
175
+ unless options[:column]
176
+ raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
177
+ end
178
+ options = options.dup
179
+ [:add_index, [table, options.delete(:column), options]]
180
+ elsif (column = options_or_column).present?
181
+ [:add_index, [table, column]]
158
182
  end
159
-
160
- options = options.dup
161
- [:add_index, [table, options.delete(:column), options]]
162
183
  end
163
184
 
164
185
  alias :invert_add_belongs_to :invert_add_reference
165
186
  alias :invert_remove_belongs_to :invert_remove_reference
166
187
 
188
+ def invert_change_column_default(args)
189
+ table, column, options = *args
190
+
191
+ unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
192
+ raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
193
+ end
194
+
195
+ [:change_column_default, [table, column, from: options[:to], to: options[:from]]]
196
+ end
197
+
167
198
  def invert_change_column_null(args)
168
199
  args[2] = !args[2]
169
200
  [:change_column_null, args]
@@ -184,6 +215,16 @@ module ActiveRecord
184
215
  [:remove_foreign_key, [from_table, options]]
185
216
  end
186
217
 
218
+ def invert_remove_foreign_key(args)
219
+ from_table, to_table, remove_options = args
220
+ raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash)
221
+
222
+ reversed_args = [from_table, to_table]
223
+ reversed_args << remove_options if remove_options
224
+
225
+ [:add_foreign_key, reversed_args]
226
+ end
227
+
187
228
  # Forwards any missing method call to the \target.
188
229
  def method_missing(method, *args, &block)
189
230
  if @delegate.respond_to?(method)
@@ -0,0 +1,126 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ module Compatibility # :nodoc: all
4
+ def self.find(version)
5
+ version = version.to_s
6
+ name = "V#{version.tr('.', '_')}"
7
+ unless const_defined?(name)
8
+ versions = constants.grep(/\AV[0-9_]+\z/).map { |s| s.to_s.delete('V').tr('_', '.').inspect }
9
+ raise ArgumentError, "Unknown migration version #{version.inspect}; expected one of #{versions.sort.join(', ')}"
10
+ end
11
+ const_get(name)
12
+ end
13
+
14
+ V5_0 = Current
15
+
16
+ module FourTwoShared
17
+ module TableDefinition
18
+ def references(*, **options)
19
+ options[:index] ||= false
20
+ super
21
+ end
22
+ alias :belongs_to :references
23
+
24
+ def timestamps(*, **options)
25
+ options[:null] = true if options[:null].nil?
26
+ super
27
+ end
28
+ end
29
+
30
+ def create_table(table_name, options = {})
31
+ if block_given?
32
+ super(table_name, options) do |t|
33
+ class << t
34
+ prepend TableDefinition
35
+ end
36
+ yield t
37
+ end
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ def change_table(table_name, options = {})
44
+ if block_given?
45
+ super(table_name, options) do |t|
46
+ class << t
47
+ prepend TableDefinition
48
+ end
49
+ yield t
50
+ end
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ def add_reference(*, **options)
57
+ options[:index] ||= false
58
+ super
59
+ end
60
+ alias :add_belongs_to :add_reference
61
+
62
+ def add_timestamps(*, **options)
63
+ options[:null] = true if options[:null].nil?
64
+ super
65
+ end
66
+
67
+ def index_exists?(table_name, column_name, options = {})
68
+ column_names = Array(column_name).map(&:to_s)
69
+ options[:name] =
70
+ if options[:name].present?
71
+ options[:name].to_s
72
+ else
73
+ index_name(table_name, column: column_names)
74
+ end
75
+ super
76
+ end
77
+
78
+ def remove_index(table_name, options = {})
79
+ options = { column: options } unless options.is_a?(Hash)
80
+ options[:name] = index_name_for_remove(table_name, options)
81
+ super(table_name, options)
82
+ end
83
+
84
+ private
85
+
86
+ def index_name_for_remove(table_name, options = {})
87
+ index_name = index_name(table_name, options)
88
+
89
+ unless index_name_exists?(table_name, index_name, true)
90
+ if options.is_a?(Hash) && options.has_key?(:name)
91
+ options_without_column = options.dup
92
+ options_without_column.delete :column
93
+ index_name_without_column = index_name(table_name, options_without_column)
94
+
95
+ return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
96
+ end
97
+
98
+ raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
99
+ end
100
+
101
+ index_name
102
+ end
103
+ end
104
+
105
+ class V4_2 < V5_0
106
+ # 4.2 is defined as a module because it needs to be shared with
107
+ # Legacy. When the time comes, V5_0 should be defined straight
108
+ # in its class.
109
+ include FourTwoShared
110
+ end
111
+
112
+ module Legacy
113
+ include FourTwoShared
114
+
115
+ def migrate(*)
116
+ ActiveSupport::Deprecation.warn \
117
+ "Directly inheriting from ActiveRecord::Migration is deprecated. " \
118
+ "Please specify the Rails release the migration was written for:\n" \
119
+ "\n" \
120
+ " class #{self.class.name} < ActiveRecord::Migration[4.2]"
121
+ super
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,58 +1,145 @@
1
+ require "monitor"
2
+
1
3
  module ActiveRecord
2
4
  module ModelSchema
3
5
  extend ActiveSupport::Concern
4
6
 
7
+ ##
8
+ # :singleton-method: primary_key_prefix_type
9
+ # :call-seq: primary_key_prefix_type
10
+ #
11
+ # The prefix type that will be prepended to every primary key column name.
12
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
13
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
14
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
15
+ # that this is a global setting for all Active Records.
16
+
17
+ ##
18
+ # :singleton-method: primary_key_prefix_type=
19
+ # :call-seq: primary_key_prefix_type=(prefix_type)
20
+ #
21
+ # Sets the prefix type that will be prepended to every primary key column name.
22
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
23
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
24
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
25
+ # that this is a global setting for all Active Records.
26
+
27
+ ##
28
+ # :singleton-method: table_name_prefix
29
+ # :call-seq: table_name_prefix
30
+ #
31
+ # The prefix string to prepend to every table name.
32
+
33
+ ##
34
+ # :singleton-method: table_name_prefix=
35
+ # :call-seq: table_name_prefix=(prefix)
36
+ #
37
+ # Sets the prefix string to prepend to every table name. So if set to "basecamp_", all table
38
+ # names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient
39
+ # way of creating a namespace for tables in a shared database. By default, the prefix is the
40
+ # empty string.
41
+ #
42
+ # If you are organising your models within modules you can add a prefix to the models within
43
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
44
+ # returns your chosen prefix.
45
+
46
+ ##
47
+ # :singleton-method: table_name_suffix
48
+ # :call-seq: table_name_suffix
49
+ #
50
+ # The suffix string to append to every table name.
51
+
52
+ ##
53
+ # :singleton-method: table_name_suffix=
54
+ # :call-seq: table_name_suffix=(suffix)
55
+ #
56
+ # Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
57
+ # "people_basecamp"). By default, the suffix is the empty string.
58
+ #
59
+ # If you are organising your models within modules, you can add a suffix to the models within
60
+ # a namespace by defining a singleton method in the parent module called table_name_suffix which
61
+ # returns your chosen suffix.
62
+
63
+ ##
64
+ # :singleton-method: schema_migrations_table_name
65
+ # :call-seq: schema_migrations_table_name
66
+ #
67
+ # The name of the schema migrations table. By default, the value is <tt>"schema_migrations"</tt>.
68
+
69
+ ##
70
+ # :singleton-method: schema_migrations_table_name=
71
+ # :call-seq: schema_migrations_table_name=(table_name)
72
+ #
73
+ # Sets the name of the schema migrations table.
74
+
75
+ ##
76
+ # :singleton-method: internal_metadata_table_name
77
+ # :call-seq: internal_metadata_table_name
78
+ #
79
+ # The name of the internal metadata table. By default, the value is <tt>"ar_internal_metadata"</tt>.
80
+
81
+ ##
82
+ # :singleton-method: internal_metadata_table_name=
83
+ # :call-seq: internal_metadata_table_name=(table_name)
84
+ #
85
+ # Sets the name of the internal metadata table.
86
+
87
+ ##
88
+ # :singleton-method: protected_environments
89
+ # :call-seq: protected_environments
90
+ #
91
+ # The array of names of environments where destructive actions should be prohibited. By default,
92
+ # the value is <tt>["production"]</tt>.
93
+
94
+ ##
95
+ # :singleton-method: protected_environments=
96
+ # :call-seq: protected_environments=(environments)
97
+ #
98
+ # Sets an array of names of environments where destructive actions should be prohibited.
99
+
100
+ ##
101
+ # :singleton-method: pluralize_table_names
102
+ # :call-seq: pluralize_table_names
103
+ #
104
+ # Indicates whether table names should be the pluralized versions of the corresponding class names.
105
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
106
+ # See table_name for the full rules on table/class naming. This is true, by default.
107
+
108
+ ##
109
+ # :singleton-method: pluralize_table_names=
110
+ # :call-seq: pluralize_table_names=(value)
111
+ #
112
+ # Set whether table names should be the pluralized versions of the corresponding class names.
113
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
114
+ # See table_name for the full rules on table/class naming. This is true, by default.
115
+
5
116
  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
117
  mattr_accessor :primary_key_prefix_type, instance_writer: false
14
118
 
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
119
  class_attribute :table_name_prefix, instance_writer: false
26
120
  self.table_name_prefix = ""
27
121
 
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
122
  class_attribute :table_name_suffix, instance_writer: false
37
123
  self.table_name_suffix = ""
38
124
 
39
- ##
40
- # :singleton-method:
41
- # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
42
125
  class_attribute :schema_migrations_table_name, instance_accessor: false
43
126
  self.schema_migrations_table_name = "schema_migrations"
44
127
 
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.
128
+ class_attribute :internal_metadata_table_name, instance_accessor: false
129
+ self.internal_metadata_table_name = "ar_internal_metadata"
130
+
131
+ class_attribute :protected_environments, instance_accessor: false
132
+ self.protected_environments = ["production"]
133
+
50
134
  class_attribute :pluralize_table_names, instance_writer: false
51
135
  self.pluralize_table_names = true
52
136
 
53
137
  self.inheritance_column = 'type'
138
+ self.ignored_columns = [].freeze
54
139
 
55
140
  delegate :type_for_attribute, to: :class
141
+
142
+ initialize_load_schema_monitor
56
143
  end
57
144
 
58
145
  # Derives the join table name for +first_table+ and +second_table+. The
@@ -111,17 +198,6 @@ module ActiveRecord
111
198
  # class Mouse < ActiveRecord::Base
112
199
  # self.table_name = "mice"
113
200
  # 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
201
  def table_name
126
202
  reset_table_name unless defined?(@table_name)
127
203
  @table_name
@@ -132,9 +208,6 @@ module ActiveRecord
132
208
  # class Project < ActiveRecord::Base
133
209
  # self.table_name = "project"
134
210
  # 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
211
  def table_name=(value)
139
212
  value = value && value.to_s
140
213
 
@@ -147,7 +220,7 @@ module ActiveRecord
147
220
  @quoted_table_name = nil
148
221
  @arel_table = nil
149
222
  @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
150
- @relation = Relation.create(self, arel_table)
223
+ @predicate_builder = nil
151
224
  end
152
225
 
153
226
  # Returns a quoted version of the table name, used to construct SQL statements.
@@ -193,6 +266,22 @@ module ActiveRecord
193
266
  @explicit_inheritance_column = true
194
267
  end
195
268
 
269
+ # The list of columns names the model should ignore. Ignored columns won't have attribute
270
+ # accessors defined, and won't be referenced in SQL queries.
271
+ def ignored_columns
272
+ if defined?(@ignored_columns)
273
+ @ignored_columns
274
+ else
275
+ superclass.ignored_columns
276
+ end
277
+ end
278
+
279
+ # Sets the columns names the model should ignore. Ignored columns won't have attribute
280
+ # accessors defined, and won't be referenced in SQL queries.
281
+ def ignored_columns=(columns)
282
+ @ignored_columns = columns.map(&:to_s)
283
+ end
284
+
196
285
  def sequence_name
197
286
  if base_class == self
198
287
  @sequence_name ||= reset_sequence_name
@@ -225,39 +314,79 @@ module ActiveRecord
225
314
  @explicit_sequence_name = true
226
315
  end
227
316
 
317
+ # Determines if the primary key values should be selected from their
318
+ # corresponding sequence before the insert statement.
319
+ def prefetch_primary_key?
320
+ connection.prefetch_primary_key?(table_name)
321
+ end
322
+
323
+ # Returns the next value that will be used as the primary key on
324
+ # an insert statement.
325
+ def next_sequence_value
326
+ connection.next_sequence_value(sequence_name)
327
+ end
328
+
228
329
  # Indicates whether the table associated with this class exists
229
330
  def table_exists?
230
- connection.schema_cache.table_exists?(table_name)
331
+ connection.schema_cache.data_source_exists?(table_name)
231
332
  end
232
333
 
233
334
  def attributes_builder # :nodoc:
234
- @attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
335
+ unless defined?(@attributes_builder) && @attributes_builder
336
+ defaults = _default_attributes.except(*(column_names - [primary_key]))
337
+ @attributes_builder = AttributeSet::Builder.new(attribute_types, defaults)
338
+ end
339
+ @attributes_builder
235
340
  end
236
341
 
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
342
+ def columns_hash # :nodoc:
343
+ load_schema
344
+ @columns_hash
345
+ end
346
+
347
+ def columns
348
+ load_schema
349
+ @columns ||= columns_hash.values
350
+ end
351
+
352
+ def attribute_types # :nodoc:
353
+ load_schema
354
+ @attribute_types ||= Hash.new(Type::Value.new)
241
355
  end
242
356
 
243
- def type_for_attribute(attr_name) # :nodoc:
244
- column_types[attr_name]
357
+ # Returns the type of the attribute with the given name, after applying
358
+ # all modifiers. This method is the only valid source of information for
359
+ # anything related to the types of a model's attributes. This method will
360
+ # access the database and load the model's schema if it is required.
361
+ #
362
+ # The return value of this method will implement the interface described
363
+ # by ActiveModel::Type::Value (though the object itself may not subclass
364
+ # it).
365
+ #
366
+ # +attr_name+ The name of the attribute to retrieve the type for. Must be
367
+ # a string
368
+ def type_for_attribute(attr_name, &block)
369
+ if block
370
+ attribute_types.fetch(attr_name, &block)
371
+ else
372
+ attribute_types[attr_name]
373
+ end
245
374
  end
246
375
 
247
376
  # Returns a hash where the keys are column names and the values are
248
- # default values when instantiating the AR object for this table.
377
+ # default values when instantiating the Active Record object for this table.
249
378
  def column_defaults
250
- _default_attributes.dup.to_hash
379
+ load_schema
380
+ _default_attributes.to_hash
251
381
  end
252
382
 
253
383
  def _default_attributes # :nodoc:
254
- @default_attributes ||= attributes_builder.build_from_database(
255
- raw_default_values)
384
+ @default_attributes ||= AttributeSet.new({})
256
385
  end
257
386
 
258
387
  # Returns an array of column names as strings.
259
388
  def column_names
260
- @column_names ||= columns.map { |column| column.name }
389
+ @column_names ||= columns.map(&:name)
261
390
  end
262
391
 
263
392
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
@@ -273,7 +402,7 @@ module ActiveRecord
273
402
  # when just after creating a table you want to populate it with some default
274
403
  # values, eg:
275
404
  #
276
- # class CreateJobLevels < ActiveRecord::Migration
405
+ # class CreateJobLevels < ActiveRecord::Migration[5.0]
277
406
  # def up
278
407
  # create_table :job_levels do |t|
279
408
  # t.integer :id
@@ -295,21 +424,71 @@ module ActiveRecord
295
424
  def reset_column_information
296
425
  connection.clear_cache!
297
426
  undefine_attribute_methods
298
- connection.schema_cache.clear_table_cache!(table_name)
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
427
+ connection.schema_cache.clear_data_source_cache!(table_name)
307
428
 
429
+ reload_schema_from_cache
308
430
  initialize_find_by_cache
309
431
  end
310
432
 
433
+ protected
434
+
435
+ def initialize_load_schema_monitor
436
+ @load_schema_monitor = Monitor.new
437
+ end
438
+
311
439
  private
312
440
 
441
+ def inherited(child_class)
442
+ super
443
+ child_class.initialize_load_schema_monitor
444
+ end
445
+
446
+ def schema_loaded?
447
+ defined?(@schema_loaded) && @schema_loaded
448
+ end
449
+
450
+ def load_schema
451
+ return if schema_loaded?
452
+ @load_schema_monitor.synchronize do
453
+ return if defined?(@columns_hash) && @columns_hash
454
+
455
+ load_schema!
456
+
457
+ @schema_loaded = true
458
+ end
459
+ end
460
+
461
+ def load_schema!
462
+ @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
463
+ @columns_hash.each do |name, column|
464
+ warn_if_deprecated_type(column)
465
+ define_attribute(
466
+ name,
467
+ connection.lookup_cast_type_from_column(column),
468
+ default: column.default,
469
+ user_provided_default: false
470
+ )
471
+ end
472
+ end
473
+
474
+ def reload_schema_from_cache
475
+ @arel_engine = nil
476
+ @arel_table = nil
477
+ @column_names = nil
478
+ @attribute_types = nil
479
+ @content_columns = nil
480
+ @default_attributes = nil
481
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
482
+ @attributes_builder = nil
483
+ @columns = nil
484
+ @columns_hash = nil
485
+ @schema_loaded = false
486
+ @attribute_names = nil
487
+ direct_descendants.each do |descendant|
488
+ descendant.send(:reload_schema_from_cache)
489
+ end
490
+ end
491
+
313
492
  # Guesses the table name, but does not decorate it with prefix and suffix information.
314
493
  def undecorated_table_name(class_name = base_class.name)
315
494
  table_name = class_name.to_s.demodulize.underscore
@@ -334,8 +513,26 @@ module ActiveRecord
334
513
  end
335
514
  end
336
515
 
337
- def raw_default_values
338
- columns_hash.transform_values(&:default)
516
+ def warn_if_deprecated_type(column)
517
+ return if attributes_to_define_after_schema_loads.key?(column.name)
518
+ if column.respond_to?(:oid) && column.sql_type.start_with?("point")
519
+ if column.array?
520
+ array_arguments = ", array: true"
521
+ else
522
+ array_arguments = ""
523
+ end
524
+ ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
525
+ The behavior of the `:point` type will be changing in Rails 5.1 to
526
+ return a `Point` object, rather than an `Array`. If you'd like to
527
+ keep the old behavior, you can add this line to #{self.name}:
528
+
529
+ attribute :#{column.name}, :legacy_point#{array_arguments}
530
+
531
+ If you'd like the new behavior today, you can add this line:
532
+
533
+ attribute :#{column.name}, :point#{array_arguments}
534
+ WARNING
535
+ end
339
536
  end
340
537
  end
341
538
  end