activerecord 5.1.5 → 5.2.8.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +655 -608
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +7 -5
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +41 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +59 -47
  22. data/lib/active_record/associations/collection_proxy.rb +20 -49
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +12 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +32 -216
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +35 -19
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +15 -1
  55. data/lib/active_record/collection_cache_key.rb +12 -8
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -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 +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -95
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +51 -61
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +18 -13
  133. data/lib/active_record/errors.rb +60 -15
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +47 -9
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +198 -49
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +4 -2
  158. data/lib/active_record/railtie.rb +80 -6
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +108 -194
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +46 -20
  167. data/lib/active_record/relation/delegation.rb +45 -27
  168. data/lib/active_record/relation/finder_methods.rb +77 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +53 -23
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +60 -79
  179. data/lib/active_record/relation/query_attribute.rb +28 -2
  180. data/lib/active_record/relation/query_methods.rb +129 -100
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +4 -2
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +120 -214
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +8 -9
  193. data/lib/active_record/scoping/named.rb +23 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +23 -13
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +33 -28
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +26 -40
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,74 +1,139 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Sanitization
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  module ClassMethods
6
- private
8
+ # Accepts an array or string of SQL conditions and sanitizes
9
+ # them into a valid SQL fragment for a WHERE clause.
10
+ #
11
+ # sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
12
+ # # => "name='foo''bar' and group_id=4"
13
+ #
14
+ # sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
15
+ # # => "name='foo''bar' and group_id='4'"
16
+ #
17
+ # sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
18
+ # # => "name='foo''bar' and group_id='4'"
19
+ #
20
+ # sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
21
+ # # => "name='foo''bar' and group_id='4'"
22
+ def sanitize_sql_for_conditions(condition)
23
+ return nil if condition.blank?
7
24
 
8
- # Accepts an array or string of SQL conditions and sanitizes
9
- # them into a valid SQL fragment for a WHERE clause.
10
- #
11
- # sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
12
- # # => "name='foo''bar' and group_id=4"
13
- #
14
- # sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
15
- # # => "name='foo''bar' and group_id='4'"
16
- #
17
- # sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
18
- # # => "name='foo''bar' and group_id='4'"
19
- #
20
- # sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
21
- # # => "name='foo''bar' and group_id='4'"
22
- def sanitize_sql_for_conditions(condition) # :doc:
23
- return nil if condition.blank?
24
-
25
- case condition
26
- when Array; sanitize_sql_array(condition)
27
- else condition
28
- end
25
+ case condition
26
+ when Array; sanitize_sql_array(condition)
27
+ else condition
29
28
  end
30
- alias :sanitize_sql :sanitize_sql_for_conditions
31
- alias :sanitize_conditions :sanitize_sql
32
- deprecate sanitize_conditions: :sanitize_sql
29
+ end
30
+ alias :sanitize_sql :sanitize_sql_for_conditions
33
31
 
34
- # Accepts an array, hash, or string of SQL conditions and sanitizes
35
- # them into a valid SQL fragment for a SET clause.
36
- #
37
- # sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
38
- # # => "name=NULL and group_id=4"
39
- #
40
- # sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4])
41
- # # => "name=NULL and group_id=4"
42
- #
43
- # Post.send(:sanitize_sql_for_assignment, { name: nil, group_id: 4 })
44
- # # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
45
- #
46
- # sanitize_sql_for_assignment("name=NULL and group_id='4'")
47
- # # => "name=NULL and group_id='4'"
48
- def sanitize_sql_for_assignment(assignments, default_table_name = table_name) # :doc:
49
- case assignments
50
- when Array; sanitize_sql_array(assignments)
51
- when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
52
- else assignments
53
- end
32
+ # Accepts an array, hash, or string of SQL conditions and sanitizes
33
+ # them into a valid SQL fragment for a SET clause.
34
+ #
35
+ # sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
36
+ # # => "name=NULL and group_id=4"
37
+ #
38
+ # sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4])
39
+ # # => "name=NULL and group_id=4"
40
+ #
41
+ # Post.sanitize_sql_for_assignment({ name: nil, group_id: 4 })
42
+ # # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
43
+ #
44
+ # sanitize_sql_for_assignment("name=NULL and group_id='4'")
45
+ # # => "name=NULL and group_id='4'"
46
+ def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
47
+ case assignments
48
+ when Array; sanitize_sql_array(assignments)
49
+ when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
50
+ else assignments
54
51
  end
52
+ end
55
53
 
56
- # Accepts an array, or string of SQL conditions and sanitizes
57
- # them into a valid SQL fragment for an ORDER clause.
58
- #
59
- # sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
60
- # # => "field(id, 1,3,2)"
61
- #
62
- # sanitize_sql_for_order("id ASC")
63
- # # => "id ASC"
64
- def sanitize_sql_for_order(condition) # :doc:
65
- if condition.is_a?(Array) && condition.first.to_s.include?("?")
66
- sanitize_sql_array(condition)
67
- else
68
- condition
54
+ # Accepts an array, or string of SQL conditions and sanitizes
55
+ # them into a valid SQL fragment for an ORDER clause.
56
+ #
57
+ # sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
58
+ # # => "field(id, 1,3,2)"
59
+ #
60
+ # sanitize_sql_for_order("id ASC")
61
+ # # => "id ASC"
62
+ def sanitize_sql_for_order(condition)
63
+ if condition.is_a?(Array) && condition.first.to_s.include?("?")
64
+ enforce_raw_sql_whitelist([condition.first],
65
+ whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
66
+ )
67
+
68
+ # Ensure we aren't dealing with a subclass of String that might
69
+ # override methods we use (eg. Arel::Nodes::SqlLiteral).
70
+ if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
71
+ condition = [String.new(condition.first), *condition[1..-1]]
69
72
  end
73
+
74
+ Arel.sql(sanitize_sql_array(condition))
75
+ else
76
+ condition
77
+ end
78
+ end
79
+
80
+ # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
81
+ #
82
+ # sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
83
+ # # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
84
+ def sanitize_sql_hash_for_assignment(attrs, table)
85
+ c = connection
86
+ attrs.map do |attr, value|
87
+ type = type_for_attribute(attr)
88
+ value = type.serialize(type.cast(value))
89
+ "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
90
+ end.join(", ")
91
+ end
92
+
93
+ # Sanitizes a +string+ so that it is safe to use within an SQL
94
+ # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
95
+ #
96
+ # sanitize_sql_like("100%")
97
+ # # => "100\\%"
98
+ #
99
+ # sanitize_sql_like("snake_cased_string")
100
+ # # => "snake\\_cased\\_string"
101
+ #
102
+ # sanitize_sql_like("100%", "!")
103
+ # # => "100!%"
104
+ #
105
+ # sanitize_sql_like("snake_cased_string", "!")
106
+ # # => "snake!_cased!_string"
107
+ def sanitize_sql_like(string, escape_character = "\\")
108
+ pattern = Regexp.union(escape_character, "%", "_")
109
+ string.gsub(pattern) { |x| [escape_character, x].join }
110
+ end
111
+
112
+ # Accepts an array of conditions. The array has each value
113
+ # sanitized and interpolated into the SQL statement.
114
+ #
115
+ # sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
116
+ # # => "name='foo''bar' and group_id=4"
117
+ #
118
+ # sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
119
+ # # => "name='foo''bar' and group_id=4"
120
+ #
121
+ # sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
122
+ # # => "name='foo''bar' and group_id='4'"
123
+ def sanitize_sql_array(ary)
124
+ statement, *values = ary
125
+ if values.first.is_a?(Hash) && /:\w+/.match?(statement)
126
+ replace_named_bind_variables(statement, values.first)
127
+ elsif statement.include?("?")
128
+ replace_bind_variables(statement, values)
129
+ elsif statement.blank?
130
+ statement
131
+ else
132
+ statement % values.collect { |value| connection.quote_string(value.to_s) }
70
133
  end
134
+ end
71
135
 
136
+ private
72
137
  # Accepts a hash of SQL conditions and replaces those attributes
73
138
  # that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of]
74
139
  # relationship with their expanded aggregate attribute values.
@@ -90,10 +155,12 @@ module ActiveRecord
90
155
  if aggregation = reflect_on_aggregation(attr.to_sym)
91
156
  mapping = aggregation.mapping
92
157
  mapping.each do |field_attr, aggregate_attr|
93
- if mapping.size == 1 && !value.respond_to?(aggregate_attr)
94
- expanded_attrs[field_attr] = value
158
+ expanded_attrs[field_attr] = if value.is_a?(Array)
159
+ value.map { |it| it.send(aggregate_attr) }
160
+ elsif mapping.size == 1 && !value.respond_to?(aggregate_attr)
161
+ value
95
162
  else
96
- expanded_attrs[field_attr] = value.send(aggregate_attr)
163
+ value.send(aggregate_attr)
97
164
  end
98
165
  end
99
166
  else
@@ -102,61 +169,7 @@ module ActiveRecord
102
169
  end
103
170
  expanded_attrs
104
171
  end
105
-
106
- # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
107
- #
108
- # sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
109
- # # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
110
- def sanitize_sql_hash_for_assignment(attrs, table) # :doc:
111
- c = connection
112
- attrs.map do |attr, value|
113
- value = type_for_attribute(attr.to_s).serialize(value)
114
- "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
115
- end.join(", ")
116
- end
117
-
118
- # Sanitizes a +string+ so that it is safe to use within an SQL
119
- # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
120
- #
121
- # sanitize_sql_like("100%")
122
- # # => "100\\%"
123
- #
124
- # sanitize_sql_like("snake_cased_string")
125
- # # => "snake\\_cased\\_string"
126
- #
127
- # sanitize_sql_like("100%", "!")
128
- # # => "100!%"
129
- #
130
- # sanitize_sql_like("snake_cased_string", "!")
131
- # # => "snake!_cased!_string"
132
- def sanitize_sql_like(string, escape_character = "\\") # :doc:
133
- pattern = Regexp.union(escape_character, "%", "_")
134
- string.gsub(pattern) { |x| [escape_character, x].join }
135
- end
136
-
137
- # Accepts an array of conditions. The array has each value
138
- # sanitized and interpolated into the SQL statement.
139
- #
140
- # sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
141
- # # => "name='foo''bar' and group_id=4"
142
- #
143
- # sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
144
- # # => "name='foo''bar' and group_id=4"
145
- #
146
- # sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
147
- # # => "name='foo''bar' and group_id='4'"
148
- def sanitize_sql_array(ary) # :doc:
149
- statement, *values = ary
150
- if values.first.is_a?(Hash) && /:\w+/.match?(statement)
151
- replace_named_bind_variables(statement, values.first)
152
- elsif statement.include?("?")
153
- replace_bind_variables(statement, values)
154
- elsif statement.blank?
155
- statement
156
- else
157
- statement % values.collect { |value| connection.quote_string(value.to_s) }
158
- end
159
- end
172
+ deprecate :expand_hash_conditions_for_aggregates
160
173
 
161
174
  def replace_bind_variables(statement, values)
162
175
  raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
@@ -205,10 +218,5 @@ module ActiveRecord
205
218
  end
206
219
  end
207
220
  end
208
-
209
- def quoted_id # :nodoc:
210
- self.class.connection.quote(@attributes[self.class.primary_key].value_for_database)
211
- end
212
- deprecate :quoted_id
213
221
  end
214
222
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record \Schema
3
5
  #
@@ -37,7 +39,7 @@ module ActiveRecord
37
39
  # The +info+ hash is optional, and if given is used to define metadata
38
40
  # about the current schema (currently, only the schema's version):
39
41
  #
40
- # ActiveRecord::Schema.define(version: 20380119000001) do
42
+ # ActiveRecord::Schema.define(version: 2038_01_19_000001) do
41
43
  # ...
42
44
  # end
43
45
  def self.define(info = {}, &block)
@@ -53,7 +55,7 @@ module ActiveRecord
53
55
  end
54
56
 
55
57
  ActiveRecord::InternalMetadata.create_table
56
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
58
+ ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
57
59
  end
58
60
 
59
61
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "stringio"
2
4
 
3
5
  module ActiveRecord
@@ -11,14 +13,13 @@ module ActiveRecord
11
13
  ##
12
14
  # :singleton-method:
13
15
  # A list of tables which should not be dumped to the schema.
14
- # Acceptable values are strings as well as regexp.
15
- # This setting is only used if ActiveRecord::Base.schema_format == :ruby
16
- cattr_accessor :ignore_tables
17
- @@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: []
18
19
 
19
20
  class << self
20
21
  def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
21
- new(connection, generate_options(config)).dump(stream)
22
+ connection.create_schema_dumper(generate_options(config)).dump(stream)
22
23
  stream
23
24
  end
24
25
 
@@ -43,13 +44,22 @@ module ActiveRecord
43
44
 
44
45
  def initialize(connection, options = {})
45
46
  @connection = connection
46
- @version = Migrator::current_version rescue nil
47
+ @version = connection.migration_context.current_version rescue nil
47
48
  @options = options
48
49
  end
49
50
 
50
- def header(stream)
51
- 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
52
57
 
58
+ def define_params
59
+ @version ? "version: #{formatted_version}" : ""
60
+ end
61
+
62
+ def header(stream)
53
63
  stream.puts <<HEADER
54
64
  # This file is auto-generated from the current state of the database. Instead
55
65
  # of editing this file, please use the migrations feature of Active Record to
@@ -72,16 +82,8 @@ HEADER
72
82
  stream.puts "end"
73
83
  end
74
84
 
85
+ # extensions are only supported by PostgreSQL
75
86
  def extensions(stream)
76
- return unless @connection.supports_extensions?
77
- extensions = @connection.extensions
78
- if extensions.any?
79
- stream.puts " # These are extensions that must be enabled in order to support this database"
80
- extensions.each do |extension|
81
- stream.puts " enable_extension #{extension.inspect}"
82
- end
83
- stream.puts
84
- end
85
87
  end
86
88
 
87
89
  def tables(stream)
@@ -113,7 +115,7 @@ HEADER
113
115
  when String
114
116
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
115
117
  pkcol = columns.detect { |c| c.name == pk }
116
- pkcolspec = @connection.column_spec_for_primary_key(pkcol)
118
+ pkcolspec = column_spec_for_primary_key(pkcol)
117
119
  if pkcolspec.present?
118
120
  tbl.print ", #{format_colspec(pkcolspec)}"
119
121
  end
@@ -122,20 +124,19 @@ HEADER
122
124
  else
123
125
  tbl.print ", id: false"
124
126
  end
125
- tbl.print ", force: :cascade"
126
127
 
127
128
  table_options = @connection.table_options(table)
128
129
  if table_options.present?
129
130
  tbl.print ", #{format_options(table_options)}"
130
131
  end
131
132
 
132
- tbl.puts " do |t|"
133
+ tbl.puts ", force: :cascade do |t|"
133
134
 
134
135
  # then dump all non-primary key columns
135
136
  columns.each do |column|
136
137
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
137
138
  next if column.name == pk
138
- type, colspec = @connection.column_spec(column)
139
+ type, colspec = column_spec(column)
139
140
  tbl.print " t.#{type} #{column.name.inspect}"
140
141
  tbl.print ", #{format_colspec(colspec)}" if colspec.present?
141
142
  tbl.puts
@@ -153,8 +154,6 @@ HEADER
153
154
  stream.puts "# #{e.message}"
154
155
  stream.puts
155
156
  end
156
-
157
- stream
158
157
  end
159
158
 
160
159
  # Keep it for indexing materialized views
@@ -185,8 +184,9 @@ HEADER
185
184
  "name: #{index.name.inspect}",
186
185
  ]
187
186
  index_parts << "unique: true" if index.unique
188
- index_parts << "length: { #{format_options(index.lengths)} }" if index.lengths.present?
189
- index_parts << "order: { #{format_options(index.orders)} }" if index.orders.present?
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
190
  index_parts << "where: #{index.where.inspect}" if index.where
191
191
  index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
192
192
  index_parts << "type: #{index.type.inspect}" if index.type
@@ -232,8 +232,18 @@ HEADER
232
232
  options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
233
233
  end
234
234
 
235
+ def format_index_parts(options)
236
+ if options.is_a?(Hash)
237
+ "{ #{format_options(options)} }"
238
+ else
239
+ options.inspect
240
+ end
241
+ end
242
+
235
243
  def remove_prefix_and_suffix(table)
236
- table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[: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")
237
247
  end
238
248
 
239
249
  def ignored?(table_name)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/scoping/default"
2
4
  require "active_record/scoping/named"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Scoping
3
5
  module Default
@@ -5,11 +7,8 @@ module ActiveRecord
5
7
 
6
8
  included do
7
9
  # Stores the default scope for the class.
8
- class_attribute :default_scopes, instance_writer: false, instance_predicate: false
9
- class_attribute :default_scope_override, instance_writer: false, instance_predicate: false
10
-
11
- self.default_scopes = []
12
- self.default_scope_override = nil
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
13
12
  end
14
13
 
15
14
  module ClassMethods
@@ -87,8 +86,8 @@ module ActiveRecord
87
86
  # # Should return a scope, you can call 'super' here etc.
88
87
  # end
89
88
  # end
90
- def default_scope(scope = nil) # :doc:
91
- scope = Proc.new if block_given?
89
+ def default_scope(scope = nil, &block) # :doc:
90
+ scope = block if block_given?
92
91
 
93
92
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
94
93
  raise ArgumentError,
@@ -112,7 +111,7 @@ module ActiveRecord
112
111
  # The user has defined their own default scope method, so call that
113
112
  evaluate_default_scope do
114
113
  if scope = default_scope
115
- (base_rel ||= relation).merge(scope)
114
+ (base_rel ||= relation).merge!(scope)
116
115
  end
117
116
  end
118
117
  elsif default_scopes.any?
@@ -120,7 +119,7 @@ module ActiveRecord
120
119
  evaluate_default_scope do
121
120
  default_scopes.inject(base_rel) do |default_scope, scope|
122
121
  scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
123
- default_scope.merge(base_rel.instance_exec(&scope))
122
+ default_scope.merge!(base_rel.instance_exec(&scope))
124
123
  end
125
124
  end
126
125
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/array"
2
4
  require "active_support/core_ext/hash/except"
3
5
  require "active_support/core_ext/kernel/singleton_class"
@@ -22,8 +24,14 @@ module ActiveRecord
22
24
  # You can define a scope that applies to all finders using
23
25
  # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
24
26
  def all
27
+ current_scope = self.current_scope
28
+
25
29
  if current_scope
26
- current_scope.clone
30
+ if self == current_scope.klass
31
+ current_scope.clone
32
+ else
33
+ relation.merge!(current_scope)
34
+ end
27
35
  else
28
36
  default_scoped
29
37
  end
@@ -163,24 +171,32 @@ module ActiveRecord
163
171
  "a class method with the same name."
164
172
  end
165
173
 
174
+ if method_defined_within?(name, Relation)
175
+ raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
176
+ "on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
177
+ "an instance method with the same name."
178
+ end
179
+
166
180
  valid_scope_name?(name)
167
181
  extension = Module.new(&block) if block
168
182
 
169
183
  if body.respond_to?(:to_proc)
170
184
  singleton_class.send(:define_method, name) do |*args|
171
- scope = all.scoping { instance_exec(*args, &body) }
185
+ scope = all
186
+ scope = scope._exec_scope(*args, &body)
172
187
  scope = scope.extending(extension) if extension
173
-
174
- scope || all
188
+ scope
175
189
  end
176
190
  else
177
191
  singleton_class.send(:define_method, name) do |*args|
178
- scope = all.scoping { body.call(*args) }
192
+ scope = all
193
+ scope = scope.scoping { body.call(*args) || scope }
179
194
  scope = scope.extending(extension) if extension
180
-
181
- scope || all
195
+ scope
182
196
  end
183
197
  end
198
+
199
+ generate_relation_method(name)
184
200
  end
185
201
 
186
202
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/per_thread_registry"
2
4
 
3
5
  module ActiveRecord
@@ -9,23 +11,23 @@ module ActiveRecord
9
11
  include Named
10
12
  end
11
13
 
12
- module ClassMethods
13
- def current_scope(skip_inherited_scope = false) # :nodoc:
14
+ module ClassMethods # :nodoc:
15
+ def current_scope(skip_inherited_scope = false)
14
16
  ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
15
17
  end
16
18
 
17
- def current_scope=(scope) #:nodoc:
19
+ def current_scope=(scope)
18
20
  ScopeRegistry.set_value_for(:current_scope, self, scope)
19
21
  end
20
22
 
21
23
  # Collects attributes from scopes that should be applied when creating
22
24
  # an AR instance for the particular class this is called on.
23
- def scope_attributes # :nodoc:
25
+ def scope_attributes
24
26
  all.scope_for_create
25
27
  end
26
28
 
27
29
  # Are there attributes associated with this scope?
28
- def scope_attributes? # :nodoc:
30
+ def scope_attributes?
29
31
  current_scope
30
32
  end
31
33
  end
@@ -33,9 +35,8 @@ module ActiveRecord
33
35
  def populate_with_current_scope_attributes # :nodoc:
34
36
  return unless self.class.scope_attributes?
35
37
 
36
- self.class.scope_attributes.each do |att, value|
37
- send("#{att}=", value) if respond_to?("#{att}=")
38
- end
38
+ attributes = self.class.scope_attributes
39
+ _assign_attributes(attributes) if attributes.any?
39
40
  end
40
41
 
41
42
  def initialize_internals_callback # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module SecureToken
3
5
  extend ActiveSupport::Concern
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord #:nodoc:
2
4
  # = Active Record \Serialization
3
5
  module Serialization