activerecord 3.2.22.5 → 5.2.8

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 (275) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -621
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +41 -46
  5. data/examples/performance.rb +55 -42
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +264 -236
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +127 -75
  11. data/lib/active_record/associations/association_scope.rb +126 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +78 -27
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
  14. data/lib/active_record/associations/builder/association.rb +117 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +135 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -54
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
  18. data/lib/active_record/associations/builder/has_many.rb +10 -64
  19. data/lib/active_record/associations/builder/has_one.rb +19 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +28 -18
  21. data/lib/active_record/associations/collection_association.rb +226 -293
  22. data/lib/active_record/associations/collection_proxy.rb +1067 -69
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +83 -47
  25. data/lib/active_record/associations/has_many_through_association.rb +98 -65
  26. data/lib/active_record/associations/has_one_association.rb +57 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +212 -164
  32. data/lib/active_record/associations/preloader/association.rb +95 -89
  33. data/lib/active_record/associations/preloader/through_association.rb +84 -44
  34. data/lib/active_record/associations/preloader.rb +123 -111
  35. data/lib/active_record/associations/singular_association.rb +33 -24
  36. data/lib/active_record/associations/through_association.rb +60 -26
  37. data/lib/active_record/associations.rb +1759 -1506
  38. data/lib/active_record/attribute_assignment.rb +60 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +113 -74
  42. data/lib/active_record/attribute_methods/primary_key.rb +106 -77
  43. data/lib/active_record/attribute_methods/query.rb +8 -5
  44. data/lib/active_record/attribute_methods/read.rb +63 -114
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -90
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
  47. data/lib/active_record/attribute_methods/write.rb +43 -45
  48. data/lib/active_record/attribute_methods.rb +366 -149
  49. data/lib/active_record/attributes.rb +266 -0
  50. data/lib/active_record/autosave_association.rb +312 -225
  51. data/lib/active_record/base.rb +114 -505
  52. data/lib/active_record/callbacks.rb +145 -67
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
  69. data/lib/active_record/connection_adapters/column.rb +50 -255
  70. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  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 +59 -210
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  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 +92 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  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 +41 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
  117. data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
  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 +545 -27
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +145 -0
  128. data/lib/active_record/core.rb +559 -0
  129. data/lib/active_record/counter_cache.rb +200 -105
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +107 -69
  132. data/lib/active_record/enum.rb +244 -0
  133. data/lib/active_record/errors.rb +245 -60
  134. data/lib/active_record/explain.rb +35 -71
  135. data/lib/active_record/explain_registry.rb +32 -0
  136. data/lib/active_record/explain_subscriber.rb +18 -9
  137. data/lib/active_record/fixture_set/file.rb +82 -0
  138. data/lib/active_record/fixtures.rb +418 -275
  139. data/lib/active_record/gem_version.rb +17 -0
  140. data/lib/active_record/inheritance.rb +209 -100
  141. data/lib/active_record/integration.rb +116 -21
  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 +9 -1
  145. data/lib/active_record/locking/optimistic.rb +107 -94
  146. data/lib/active_record/locking/pessimistic.rb +20 -8
  147. data/lib/active_record/log_subscriber.rb +99 -34
  148. data/lib/active_record/migration/command_recorder.rb +199 -64
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +17 -0
  151. data/lib/active_record/migration.rb +893 -296
  152. data/lib/active_record/model_schema.rb +328 -175
  153. data/lib/active_record/nested_attributes.rb +338 -242
  154. data/lib/active_record/no_touching.rb +58 -0
  155. data/lib/active_record/null_relation.rb +68 -0
  156. data/lib/active_record/persistence.rb +557 -170
  157. data/lib/active_record/query_cache.rb +14 -43
  158. data/lib/active_record/querying.rb +36 -24
  159. data/lib/active_record/railtie.rb +147 -52
  160. data/lib/active_record/railties/console_sandbox.rb +5 -4
  161. data/lib/active_record/railties/controller_runtime.rb +13 -6
  162. data/lib/active_record/railties/databases.rake +206 -488
  163. data/lib/active_record/readonly_attributes.rb +4 -6
  164. data/lib/active_record/reflection.rb +734 -228
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +249 -52
  167. data/lib/active_record/relation/calculations.rb +330 -284
  168. data/lib/active_record/relation/delegation.rb +135 -37
  169. data/lib/active_record/relation/finder_methods.rb +450 -287
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +193 -0
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  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 +19 -0
  179. data/lib/active_record/relation/predicate_builder.rb +132 -43
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +1037 -221
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +48 -151
  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 +451 -359
  187. data/lib/active_record/result.rb +129 -20
  188. data/lib/active_record/runtime_registry.rb +24 -0
  189. data/lib/active_record/sanitization.rb +164 -136
  190. data/lib/active_record/schema.rb +31 -19
  191. data/lib/active_record/schema_dumper.rb +154 -107
  192. data/lib/active_record/schema_migration.rb +56 -0
  193. data/lib/active_record/scoping/default.rb +108 -98
  194. data/lib/active_record/scoping/named.rb +125 -112
  195. data/lib/active_record/scoping.rb +77 -123
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +10 -6
  198. data/lib/active_record/statement_cache.rb +121 -0
  199. data/lib/active_record/store.rb +175 -16
  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 +337 -0
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  206. data/lib/active_record/timestamp.rb +80 -41
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +240 -119
  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 +9 -0
  212. data/lib/active_record/type/date_time.rb +9 -0
  213. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  214. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  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 +71 -0
  218. data/lib/active_record/type/text.rb +11 -0
  219. data/lib/active_record/type/time.rb +21 -0
  220. data/lib/active_record/type/type_map.rb +62 -0
  221. data/lib/active_record/type/unsigned_integer.rb +17 -0
  222. data/lib/active_record/type.rb +79 -0
  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 +35 -18
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +68 -0
  230. data/lib/active_record/validations/uniqueness.rb +133 -75
  231. data/lib/active_record/validations.rb +53 -43
  232. data/lib/active_record/version.rb +7 -7
  233. data/lib/active_record.rb +89 -57
  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 +61 -8
  237. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  238. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  239. data/lib/rails/generators/active_record/migration.rb +28 -8
  240. data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
  241. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  243. data/lib/rails/generators/active_record.rb +10 -16
  244. metadata +141 -62
  245. data/examples/associations.png +0 -0
  246. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  247. data/lib/active_record/associations/join_helper.rb +0 -55
  248. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  249. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  250. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  251. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  252. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  253. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  254. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  255. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  256. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  257. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  258. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  259. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  260. data/lib/active_record/dynamic_finder_match.rb +0 -68
  261. data/lib/active_record/dynamic_scope_match.rb +0 -23
  262. data/lib/active_record/fixtures/file.rb +0 -65
  263. data/lib/active_record/identity_map.rb +0 -162
  264. data/lib/active_record/observer.rb +0 -121
  265. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  266. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  267. data/lib/active_record/session_store.rb +0 -360
  268. data/lib/active_record/test_case.rb +0 -73
  269. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  270. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  271. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  272. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  273. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  274. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  275. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,5 +1,6 @@
1
- require 'stringio'
2
- require 'active_support/core_ext/big_decimal'
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
3
4
 
4
5
  module ActiveRecord
5
6
  # = Active Record Schema Dumper
@@ -12,18 +13,28 @@ module ActiveRecord
12
13
  ##
13
14
  # :singleton-method:
14
15
  # A list of tables which should not be dumped to the schema.
15
- # Acceptable values are strings as well as regexp.
16
- # This setting is only used if ActiveRecord::Base.schema_format == :ruby
17
- cattr_accessor :ignore_tables
18
- @@ignore_tables = []
16
+ # Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
17
+ # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
18
+ cattr_accessor :ignore_tables, default: []
19
19
 
20
- def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
21
- new(connection).dump(stream)
22
- stream
20
+ class << self
21
+ def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
22
+ connection.create_schema_dumper(generate_options(config)).dump(stream)
23
+ stream
24
+ end
25
+
26
+ private
27
+ def generate_options(config)
28
+ {
29
+ table_name_prefix: config.table_name_prefix,
30
+ table_name_suffix: config.table_name_suffix
31
+ }
32
+ end
23
33
  end
24
34
 
25
35
  def dump(stream)
26
36
  header(stream)
37
+ extensions(stream)
27
38
  tables(stream)
28
39
  trailer(stream)
29
40
  stream
@@ -31,19 +42,24 @@ module ActiveRecord
31
42
 
32
43
  private
33
44
 
34
- def initialize(connection)
45
+ def initialize(connection, options = {})
35
46
  @connection = connection
36
- @types = @connection.native_database_types
37
- @version = Migrator::current_version rescue nil
47
+ @version = connection.migration_context.current_version rescue nil
48
+ @options = options
38
49
  end
39
50
 
40
- def header(stream)
41
- define_params = @version ? ":version => #{@version}" : ""
51
+ # turns 20170404131909 into "2017_04_04_131909"
52
+ def formatted_version
53
+ stringified = @version.to_s
54
+ return stringified unless stringified.length == 14
55
+ stringified.insert(4, "_").insert(7, "_").insert(10, "_")
56
+ end
42
57
 
43
- if stream.respond_to?(:external_encoding) && stream.external_encoding
44
- stream.puts "# encoding: #{stream.external_encoding.name}"
45
- end
58
+ def define_params
59
+ @version ? "version: #{formatted_version}" : ""
60
+ end
46
61
 
62
+ def header(stream)
47
63
  stream.puts <<HEADER
48
64
  # This file is auto-generated from the current state of the database. Instead
49
65
  # of editing this file, please use the migrations feature of Active Record to
@@ -55,7 +71,7 @@ module ActiveRecord
55
71
  # from scratch. The latter is a flawed and unsustainable approach (the more migrations
56
72
  # you'll amass, the slower it'll run and the greater likelihood for issues).
57
73
  #
58
- # It's strongly recommended to check this file into your version control system.
74
+ # It's strongly recommended that you check this file into your version control system.
59
75
 
60
76
  ActiveRecord::Schema.define(#{define_params}) do
61
77
 
@@ -66,17 +82,22 @@ HEADER
66
82
  stream.puts "end"
67
83
  end
68
84
 
85
+ # extensions are only supported by PostgreSQL
86
+ def extensions(stream)
87
+ end
88
+
69
89
  def tables(stream)
70
- @connection.tables.sort.each do |tbl|
71
- next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
72
- case ignored
73
- when String; remove_prefix_and_suffix(tbl) == ignored
74
- when Regexp; remove_prefix_and_suffix(tbl) =~ ignored
75
- else
76
- raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
77
- end
90
+ sorted_tables = @connection.tables.sort
91
+
92
+ sorted_tables.each do |table_name|
93
+ table(table_name, stream) unless ignored?(table_name)
94
+ end
95
+
96
+ # dump foreign keys at the end to make sure all dependent tables exist.
97
+ if @connection.supports_foreign_keys?
98
+ sorted_tables.each do |tbl|
99
+ foreign_keys(tbl, stream) unless ignored?(tbl)
78
100
  end
79
- table(tbl, stream)
80
101
  end
81
102
  end
82
103
 
@@ -86,75 +107,46 @@ HEADER
86
107
  tbl = StringIO.new
87
108
 
88
109
  # first dump primary key column
89
- if @connection.respond_to?(:pk_and_sequence_for)
90
- pk, _ = @connection.pk_and_sequence_for(table)
91
- elsif @connection.respond_to?(:primary_key)
92
- pk = @connection.primary_key(table)
93
- end
110
+ pk = @connection.primary_key(table)
94
111
 
95
112
  tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
96
- if columns.detect { |c| c.name == pk }
97
- if pk != 'id'
98
- tbl.print %Q(, :primary_key => "#{pk}")
113
+
114
+ case pk
115
+ when String
116
+ tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
117
+ pkcol = columns.detect { |c| c.name == pk }
118
+ pkcolspec = column_spec_for_primary_key(pkcol)
119
+ if pkcolspec.present?
120
+ tbl.print ", #{format_colspec(pkcolspec)}"
99
121
  end
122
+ when Array
123
+ tbl.print ", primary_key: #{pk.inspect}"
100
124
  else
101
- tbl.print ", :id => false"
125
+ tbl.print ", id: false"
102
126
  end
103
- tbl.print ", :force => true"
104
- tbl.puts " do |t|"
127
+
128
+ table_options = @connection.table_options(table)
129
+ if table_options.present?
130
+ tbl.print ", #{format_options(table_options)}"
131
+ end
132
+
133
+ tbl.puts ", force: :cascade do |t|"
105
134
 
106
135
  # then dump all non-primary key columns
107
- column_specs = columns.map do |column|
108
- raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
136
+ columns.each do |column|
137
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
109
138
  next if column.name == pk
110
- spec = {}
111
- spec[:name] = column.name.inspect
112
-
113
- # AR has an optimization which handles zero-scale decimals as integers. This
114
- # code ensures that the dumper still dumps the column as a decimal.
115
- spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
116
- 'decimal'
117
- else
118
- column.type.to_s
119
- end
120
- spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
121
- spec[:precision] = column.precision.inspect if column.precision
122
- spec[:scale] = column.scale.inspect if column.scale
123
- spec[:null] = 'false' unless column.null
124
- spec[:default] = default_string(column.default) if column.has_default?
125
- (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
126
- spec
127
- end.compact
128
-
129
- # find all migration keys used in this table
130
- keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map{ |k| k.keys }.flatten
131
-
132
- # figure out the lengths for each column based on above keys
133
- lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
134
-
135
- # the string we're going to sprintf our values against, with standardized column widths
136
- format_string = lengths.map{ |len| "%-#{len}s" }
137
-
138
- # find the max length for the 'type' column, which is special
139
- type_length = column_specs.map{ |column| column[:type].length }.max
140
-
141
- # add column type definition to our format string
142
- format_string.unshift " t.%-#{type_length}s "
143
-
144
- format_string *= ''
145
-
146
- column_specs.each do |colspec|
147
- values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
148
- values.unshift colspec[:type]
149
- tbl.print((format_string % values).gsub(/,\s*$/, ''))
139
+ type, colspec = column_spec(column)
140
+ tbl.print " t.#{type} #{column.name.inspect}"
141
+ tbl.print ", #{format_colspec(colspec)}" if colspec.present?
150
142
  tbl.puts
151
143
  end
152
144
 
145
+ indexes_in_create(table, tbl)
146
+
153
147
  tbl.puts " end"
154
148
  tbl.puts
155
149
 
156
- indexes(table, tbl)
157
-
158
150
  tbl.rewind
159
151
  stream.print tbl.read
160
152
  rescue => e
@@ -162,47 +154,102 @@ HEADER
162
154
  stream.puts "# #{e.message}"
163
155
  stream.puts
164
156
  end
165
-
166
- stream
167
157
  end
168
158
 
169
- def default_string(value)
170
- case value
171
- when BigDecimal
172
- value.to_s
173
- when Date, DateTime, Time
174
- "'" + value.to_s(:db) + "'"
175
- else
176
- value.inspect
159
+ # Keep it for indexing materialized views
160
+ def indexes(table, stream)
161
+ if (indexes = @connection.indexes(table)).any?
162
+ add_index_statements = indexes.map do |index|
163
+ table_name = remove_prefix_and_suffix(index.table).inspect
164
+ " add_index #{([table_name] + index_parts(index)).join(', ')}"
165
+ end
166
+
167
+ stream.puts add_index_statements.sort.join("\n")
168
+ stream.puts
177
169
  end
178
170
  end
179
171
 
180
- def indexes(table, stream)
172
+ def indexes_in_create(table, stream)
181
173
  if (indexes = @connection.indexes(table)).any?
182
- add_index_statements = indexes.map do |index|
183
- statement_parts = [
184
- ('add_index ' + remove_prefix_and_suffix(index.table).inspect),
185
- index.columns.inspect,
186
- (':name => ' + index.name.inspect),
174
+ index_statements = indexes.map do |index|
175
+ " t.index #{index_parts(index).join(', ')}"
176
+ end
177
+ stream.puts index_statements.sort.join("\n")
178
+ end
179
+ end
180
+
181
+ def index_parts(index)
182
+ index_parts = [
183
+ index.columns.inspect,
184
+ "name: #{index.name.inspect}",
185
+ ]
186
+ index_parts << "unique: true" if index.unique
187
+ index_parts << "length: #{format_index_parts(index.lengths)}" if index.lengths.present?
188
+ index_parts << "order: #{format_index_parts(index.orders)}" if index.orders.present?
189
+ index_parts << "opclass: #{format_index_parts(index.opclasses)}" if index.opclasses.present?
190
+ index_parts << "where: #{index.where.inspect}" if index.where
191
+ index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
192
+ index_parts << "type: #{index.type.inspect}" if index.type
193
+ index_parts << "comment: #{index.comment.inspect}" if index.comment
194
+ index_parts
195
+ end
196
+
197
+ def foreign_keys(table, stream)
198
+ if (foreign_keys = @connection.foreign_keys(table)).any?
199
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
200
+ parts = [
201
+ "add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
202
+ remove_prefix_and_suffix(foreign_key.to_table).inspect,
187
203
  ]
188
- statement_parts << ':unique => true' if index.unique
189
204
 
190
- index_lengths = (index.lengths || []).compact
191
- statement_parts << (':length => ' + Hash[index.columns.zip(index.lengths)].inspect) unless index_lengths.empty?
205
+ if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
206
+ parts << "column: #{foreign_key.column.inspect}"
207
+ end
208
+
209
+ if foreign_key.custom_primary_key?
210
+ parts << "primary_key: #{foreign_key.primary_key.inspect}"
211
+ end
212
+
213
+ if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
214
+ parts << "name: #{foreign_key.name.inspect}"
215
+ end
192
216
 
193
- index_orders = (index.orders || {})
194
- statement_parts << (':order => ' + index.orders.inspect) unless index_orders.empty?
217
+ parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
218
+ parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
195
219
 
196
- ' ' + statement_parts.join(', ')
220
+ " #{parts.join(', ')}"
197
221
  end
198
222
 
199
- stream.puts add_index_statements.sort.join("\n")
200
- stream.puts
223
+ stream.puts add_foreign_key_statements.sort.join("\n")
224
+ end
225
+ end
226
+
227
+ def format_colspec(colspec)
228
+ colspec.map { |key, value| "#{key}: #{value}" }.join(", ")
229
+ end
230
+
231
+ def format_options(options)
232
+ options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
233
+ end
234
+
235
+ def format_index_parts(options)
236
+ if options.is_a?(Hash)
237
+ "{ #{format_options(options)} }"
238
+ else
239
+ options.inspect
201
240
  end
202
241
  end
203
242
 
204
243
  def remove_prefix_and_suffix(table)
205
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
244
+ prefix = Regexp.escape(@options[:table_name_prefix].to_s)
245
+ suffix = Regexp.escape(@options[:table_name_suffix].to_s)
246
+ table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
247
+ end
248
+
249
+ def ignored?(table_name)
250
+ [ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
251
+ ignored === remove_prefix_and_suffix(table_name)
252
+ end
206
253
  end
207
254
  end
208
255
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/scoping/default"
4
+ require "active_record/scoping/named"
5
+
6
+ module ActiveRecord
7
+ # This class is used to create a table that keeps track of which migrations
8
+ # have been applied to a given database. When a migration is run, its schema
9
+ # number is inserted in to the `SchemaMigration.table_name` so it doesn't need
10
+ # to be executed the next time.
11
+ class SchemaMigration < ActiveRecord::Base # :nodoc:
12
+ class << self
13
+ def primary_key
14
+ "version"
15
+ end
16
+
17
+ def table_name
18
+ "#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
19
+ end
20
+
21
+ def table_exists?
22
+ connection.table_exists?(table_name)
23
+ end
24
+
25
+ def create_table
26
+ unless table_exists?
27
+ version_options = connection.internal_string_options_for_primary_key
28
+
29
+ connection.create_table(table_name, id: false) do |t|
30
+ t.string :version, version_options
31
+ end
32
+ end
33
+ end
34
+
35
+ def drop_table
36
+ connection.drop_table table_name, if_exists: true
37
+ end
38
+
39
+ def normalize_migration_number(number)
40
+ "%.3d" % number.to_i
41
+ end
42
+
43
+ def normalized_versions
44
+ all_versions.map { |v| normalize_migration_number v }
45
+ end
46
+
47
+ def all_versions
48
+ order(:version).pluck(:version)
49
+ end
50
+ end
51
+
52
+ def version
53
+ super.to_i
54
+ end
55
+ end
56
+ end
@@ -1,4 +1,4 @@
1
- require 'active_support/concern'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  module Scoping
@@ -6,136 +6,146 @@ module ActiveRecord
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- # Stores the default scope for the class
10
- class_attribute :default_scopes, :instance_writer => false
11
- self.default_scopes = []
9
+ # Stores the default scope for the class.
10
+ class_attribute :default_scopes, instance_writer: false, instance_predicate: false, default: []
11
+ class_attribute :default_scope_override, instance_writer: false, instance_predicate: false, default: nil
12
12
  end
13
13
 
14
14
  module ClassMethods
15
- # Returns a scope for the model without the default_scope.
15
+ # Returns a scope for the model without the previously set scopes.
16
16
  #
17
17
  # class Post < ActiveRecord::Base
18
18
  # def self.default_scope
19
- # where :published => true
19
+ # where(published: true)
20
20
  # end
21
21
  # end
22
22
  #
23
- # Post.all # Fires "SELECT * FROM posts WHERE published = true"
24
- # Post.unscoped.all # Fires "SELECT * FROM posts"
23
+ # Post.all # Fires "SELECT * FROM posts WHERE published = true"
24
+ # Post.unscoped.all # Fires "SELECT * FROM posts"
25
+ # Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
25
26
  #
26
27
  # This method also accepts a block. All queries inside the block will
27
- # not use the default_scope:
28
+ # not use the previously set scopes.
28
29
  #
29
30
  # Post.unscoped {
30
31
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
31
32
  # }
32
- #
33
- # It is recommended to use the block form of unscoped because chaining
34
- # unscoped with <tt>scope</tt> does not work. Assuming that
35
- # <tt>published</tt> is a <tt>scope</tt>, the following two statements
36
- # are equal: the default_scope is applied on both.
37
- #
38
- # Post.unscoped.published
39
- # Post.published
40
- def unscoped #:nodoc:
33
+ def unscoped
41
34
  block_given? ? relation.scoping { yield } : relation
42
35
  end
43
36
 
37
+ # Are there attributes associated with this scope?
38
+ def scope_attributes? # :nodoc:
39
+ super || default_scopes.any? || respond_to?(:default_scope)
40
+ end
41
+
44
42
  def before_remove_const #:nodoc:
45
43
  self.current_scope = nil
46
44
  end
47
45
 
48
- protected
46
+ private
49
47
 
50
- # Use this macro in your model to set a default scope for all operations on
51
- # the model.
52
- #
53
- # class Article < ActiveRecord::Base
54
- # default_scope where(:published => true)
55
- # end
56
- #
57
- # Article.all # => SELECT * FROM articles WHERE published = true
58
- #
59
- # The <tt>default_scope</tt> is also applied while creating/building a record. It is not
60
- # applied while updating a record.
61
- #
62
- # Article.new.published # => true
63
- # Article.create.published # => true
64
- #
65
- # You can also use <tt>default_scope</tt> with a block, in order to have it lazily evaluated:
66
- #
67
- # class Article < ActiveRecord::Base
68
- # default_scope { where(:published_at => Time.now - 1.week) }
69
- # end
70
- #
71
- # (You can also pass any object which responds to <tt>call</tt> to the <tt>default_scope</tt>
72
- # macro, and it will be called when building the default scope.)
73
- #
74
- # If you use multiple <tt>default_scope</tt> declarations in your model then they will
75
- # be merged together:
76
- #
77
- # class Article < ActiveRecord::Base
78
- # default_scope where(:published => true)
79
- # default_scope where(:rating => 'G')
80
- # end
81
- #
82
- # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
83
- #
84
- # This is also the case with inheritance and module includes where the parent or module
85
- # defines a <tt>default_scope</tt> and the child or including class defines a second one.
86
- #
87
- # If you need to do more complex things with a default scope, you can alternatively
88
- # define it as a class method:
89
- #
90
- # class Article < ActiveRecord::Base
91
- # def self.default_scope
92
- # # Should return a scope, you can call 'super' here etc.
93
- # end
94
- # end
95
- def default_scope(scope = {})
96
- scope = Proc.new if block_given?
97
- self.default_scopes = default_scopes + [scope]
98
- end
48
+ # Use this macro in your model to set a default scope for all operations on
49
+ # the model.
50
+ #
51
+ # class Article < ActiveRecord::Base
52
+ # default_scope { where(published: true) }
53
+ # end
54
+ #
55
+ # Article.all # => SELECT * FROM articles WHERE published = true
56
+ #
57
+ # The #default_scope is also applied while creating/building a record.
58
+ # It is not applied while updating a record.
59
+ #
60
+ # Article.new.published # => true
61
+ # Article.create.published # => true
62
+ #
63
+ # (You can also pass any object which responds to +call+ to the
64
+ # +default_scope+ macro, and it will be called when building the
65
+ # default scope.)
66
+ #
67
+ # If you use multiple #default_scope declarations in your model then
68
+ # they will be merged together:
69
+ #
70
+ # class Article < ActiveRecord::Base
71
+ # default_scope { where(published: true) }
72
+ # default_scope { where(rating: 'G') }
73
+ # end
74
+ #
75
+ # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
76
+ #
77
+ # This is also the case with inheritance and module includes where the
78
+ # parent or module defines a #default_scope and the child or including
79
+ # class defines a second one.
80
+ #
81
+ # If you need to do more complex things with a default scope, you can
82
+ # alternatively define it as a class method:
83
+ #
84
+ # class Article < ActiveRecord::Base
85
+ # def self.default_scope
86
+ # # Should return a scope, you can call 'super' here etc.
87
+ # end
88
+ # end
89
+ def default_scope(scope = nil, &block) # :doc:
90
+ scope = block if block_given?
91
+
92
+ if scope.is_a?(Relation) || !scope.respond_to?(:call)
93
+ raise ArgumentError,
94
+ "Support for calling #default_scope without a block is removed. For example instead " \
95
+ "of `default_scope where(color: 'red')`, please use " \
96
+ "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
97
+ "self.default_scope.)"
98
+ end
99
+
100
+ self.default_scopes += [scope]
101
+ end
102
+
103
+ def build_default_scope(base_rel = nil)
104
+ return if abstract_class?
105
+
106
+ if default_scope_override.nil?
107
+ self.default_scope_override = !Base.is_a?(method(:default_scope).owner)
108
+ end
99
109
 
100
- def build_default_scope #:nodoc:
101
- if method(:default_scope).owner != ActiveRecord::Scoping::Default::ClassMethods
102
- evaluate_default_scope { default_scope }
103
- elsif default_scopes.any?
104
- evaluate_default_scope do
105
- default_scopes.inject(relation) do |default_scope, scope|
106
- if scope.is_a?(Hash)
107
- default_scope.apply_finder_options(scope)
108
- elsif !scope.is_a?(Relation) && scope.respond_to?(:call)
109
- default_scope.merge(scope.call)
110
- else
111
- default_scope.merge(scope)
110
+ if default_scope_override
111
+ # The user has defined their own default scope method, so call that
112
+ evaluate_default_scope do
113
+ if scope = default_scope
114
+ (base_rel ||= relation).merge!(scope)
115
+ end
116
+ end
117
+ elsif default_scopes.any?
118
+ base_rel ||= relation
119
+ evaluate_default_scope do
120
+ default_scopes.inject(base_rel) do |default_scope, scope|
121
+ scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
122
+ default_scope.merge!(base_rel.instance_exec(&scope))
112
123
  end
113
124
  end
114
125
  end
115
126
  end
116
- end
117
127
 
118
- def ignore_default_scope? #:nodoc:
119
- Thread.current["#{self}_ignore_default_scope"]
120
- end
128
+ def ignore_default_scope?
129
+ ScopeRegistry.value_for(:ignore_default_scope, base_class)
130
+ end
121
131
 
122
- def ignore_default_scope=(ignore) #:nodoc:
123
- Thread.current["#{self}_ignore_default_scope"] = ignore
124
- end
132
+ def ignore_default_scope=(ignore)
133
+ ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
134
+ end
125
135
 
126
- # The ignore_default_scope flag is used to prevent an infinite recursion situation where
127
- # a default scope references a scope which has a default scope which references a scope...
128
- def evaluate_default_scope
129
- return if ignore_default_scope?
136
+ # The ignore_default_scope flag is used to prevent an infinite recursion
137
+ # situation where a default scope references a scope which has a default
138
+ # scope which references a scope...
139
+ def evaluate_default_scope
140
+ return if ignore_default_scope?
130
141
 
131
- begin
132
- self.ignore_default_scope = true
133
- yield
134
- ensure
135
- self.ignore_default_scope = false
142
+ begin
143
+ self.ignore_default_scope = true
144
+ yield
145
+ ensure
146
+ self.ignore_default_scope = false
147
+ end
136
148
  end
137
- end
138
-
139
149
  end
140
150
  end
141
151
  end