activerecord 4.2.11.1 → 5.0.0

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 (246) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1282 -1195
  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 +8 -4
  8. data/lib/active_record/aggregations.rb +35 -24
  9. data/lib/active_record/association_relation.rb +3 -3
  10. data/lib/active_record/associations.rb +317 -209
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +11 -9
  13. data/lib/active_record/associations/association_scope.rb +73 -102
  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 +14 -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 +3 -10
  22. data/lib/active_record/associations/collection_association.rb +49 -41
  23. data/lib/active_record/associations/collection_proxy.rb +67 -27
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +20 -71
  26. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +29 -19
  29. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  30. data/lib/active_record/associations/preloader.rb +14 -4
  31. data/lib/active_record/associations/preloader/association.rb +46 -52
  32. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  33. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  35. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  36. data/lib/active_record/associations/singular_association.rb +7 -1
  37. data/lib/active_record/associations/through_association.rb +11 -3
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  40. data/lib/active_record/attribute_assignment.rb +19 -140
  41. data/lib/active_record/attribute_decorators.rb +6 -5
  42. data/lib/active_record/attribute_methods.rb +76 -47
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  44. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  45. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  46. data/lib/active_record/attribute_methods/query.rb +2 -2
  47. data/lib/active_record/attribute_methods/read.rb +31 -59
  48. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  50. data/lib/active_record/attribute_methods/write.rb +13 -37
  51. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attribute_set/builder.rb +6 -4
  54. data/lib/active_record/attributes.rb +199 -81
  55. data/lib/active_record/autosave_association.rb +49 -16
  56. data/lib/active_record/base.rb +32 -23
  57. data/lib/active_record/callbacks.rb +39 -43
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +20 -8
  60. data/lib/active_record/collection_cache_key.rb +40 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  62. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  63. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  64. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  65. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
  66. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  67. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  69. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  70. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
  71. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  72. data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
  73. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
  74. data/lib/active_record/connection_adapters/column.rb +28 -43
  75. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  76. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  77. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  78. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  79. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  80. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  84. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  85. data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  88. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
  91. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +37 -14
  121. data/lib/active_record/core.rb +89 -107
  122. data/lib/active_record/counter_cache.rb +13 -24
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +113 -76
  125. data/lib/active_record/errors.rb +87 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +76 -40
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +15 -15
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration.rb +363 -133
  140. data/lib/active_record/migration/command_recorder.rb +59 -18
  141. data/lib/active_record/migration/compatibility.rb +126 -0
  142. data/lib/active_record/model_schema.rb +129 -41
  143. data/lib/active_record/nested_attributes.rb +58 -29
  144. data/lib/active_record/null_relation.rb +16 -8
  145. data/lib/active_record/persistence.rb +121 -80
  146. data/lib/active_record/query_cache.rb +15 -18
  147. data/lib/active_record/querying.rb +10 -9
  148. data/lib/active_record/railtie.rb +23 -16
  149. data/lib/active_record/railties/controller_runtime.rb +1 -1
  150. data/lib/active_record/railties/databases.rake +69 -46
  151. data/lib/active_record/readonly_attributes.rb +1 -1
  152. data/lib/active_record/reflection.rb +282 -115
  153. data/lib/active_record/relation.rb +176 -116
  154. data/lib/active_record/relation/batches.rb +139 -34
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  156. data/lib/active_record/relation/calculations.rb +79 -108
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +163 -81
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +16 -42
  161. data/lib/active_record/relation/predicate_builder.rb +120 -107
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  163. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  164. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  166. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  167. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  168. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  169. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +308 -244
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +4 -7
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/result.rb +4 -3
  177. data/lib/active_record/runtime_registry.rb +1 -1
  178. data/lib/active_record/sanitization.rb +95 -66
  179. data/lib/active_record/schema.rb +26 -22
  180. data/lib/active_record/schema_dumper.rb +62 -38
  181. data/lib/active_record/schema_migration.rb +11 -14
  182. data/lib/active_record/scoping.rb +32 -15
  183. data/lib/active_record/scoping/default.rb +23 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/secure_token.rb +38 -0
  186. data/lib/active_record/serialization.rb +2 -4
  187. data/lib/active_record/statement_cache.rb +16 -14
  188. data/lib/active_record/store.rb +8 -3
  189. data/lib/active_record/suppressor.rb +58 -0
  190. data/lib/active_record/table_metadata.rb +68 -0
  191. data/lib/active_record/tasks/database_tasks.rb +57 -43
  192. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  193. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  194. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  195. data/lib/active_record/timestamp.rb +20 -9
  196. data/lib/active_record/touch_later.rb +58 -0
  197. data/lib/active_record/transactions.rb +138 -56
  198. data/lib/active_record/type.rb +66 -17
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -45
  201. data/lib/active_record/type/date_time.rb +2 -49
  202. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  203. data/lib/active_record/type/internal/timezone.rb +15 -0
  204. data/lib/active_record/type/serialized.rb +15 -14
  205. data/lib/active_record/type/time.rb +10 -16
  206. data/lib/active_record/type/type_map.rb +4 -4
  207. data/lib/active_record/type_caster.rb +7 -0
  208. data/lib/active_record/type_caster/connection.rb +29 -0
  209. data/lib/active_record/type_caster/map.rb +19 -0
  210. data/lib/active_record/validations.rb +33 -32
  211. data/lib/active_record/validations/absence.rb +23 -0
  212. data/lib/active_record/validations/associated.rb +10 -3
  213. data/lib/active_record/validations/length.rb +24 -0
  214. data/lib/active_record/validations/presence.rb +11 -12
  215. data/lib/active_record/validations/uniqueness.rb +30 -29
  216. data/lib/rails/generators/active_record/migration.rb +7 -0
  217. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  218. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  219. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +59 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -64
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. data/lib/active_record/type/value.rb +0 -110
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  module ClassMethods
12
- # Returns an <tt>ActiveRecord::Relation</tt> scope object.
12
+ # Returns an ActiveRecord::Relation scope object.
13
13
  #
14
14
  # posts = Post.all
15
15
  # posts.size # Fires "select count(*) from posts" and returns the count
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  # fruits = fruits.limit(10) if limited?
21
21
  #
22
22
  # You can define a scope that applies to all finders using
23
- # <tt>ActiveRecord::Base.default_scope</tt>.
23
+ # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
24
24
  def all
25
25
  if current_scope
26
26
  current_scope.clone
@@ -30,22 +30,22 @@ module ActiveRecord
30
30
  end
31
31
 
32
32
  def default_scoped # :nodoc:
33
- relation.merge(build_default_scope)
34
- end
35
-
36
- # Collects attributes from scopes that should be applied when creating
37
- # an AR instance for the particular class this is called on.
38
- def scope_attributes # :nodoc:
39
- all.scope_for_create
40
- end
33
+ scope = build_default_scope
41
34
 
42
- # Are there default attributes associated with this scope?
43
- def scope_attributes? # :nodoc:
44
- current_scope || default_scopes.any?
35
+ if scope
36
+ relation.spawn.merge!(scope)
37
+ else
38
+ relation
39
+ end
45
40
  end
46
41
 
47
- # Adds a class method for retrieving and querying objects. A \scope
48
- # represents a narrowing of a database query, such as
42
+ # Adds a class method for retrieving and querying objects.
43
+ # The method is intended to return an ActiveRecord::Relation
44
+ # object, which is composable with other scopes.
45
+ # If it returns nil or false, an
46
+ # {all}[rdoc-ref:Scoping::Named::ClassMethods#all] scope is returned instead.
47
+ #
48
+ # A \scope represents a narrowing of a database query, such as
49
49
  # <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
50
50
  #
51
51
  # class Shirt < ActiveRecord::Base
@@ -53,12 +53,12 @@ module ActiveRecord
53
53
  # scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
54
54
  # end
55
55
  #
56
- # The above calls to +scope+ define class methods <tt>Shirt.red</tt> and
56
+ # The above calls to #scope define class methods <tt>Shirt.red</tt> and
57
57
  # <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
58
58
  # represents the query <tt>Shirt.where(color: 'red')</tt>.
59
59
  #
60
60
  # You should always pass a callable object to the scopes defined
61
- # with +scope+. This ensures that the scope is re-evaluated each
61
+ # with #scope. This ensures that the scope is re-evaluated each
62
62
  # time it is called.
63
63
  #
64
64
  # Note that this is simply 'syntactic sugar' for defining an actual
@@ -71,14 +71,15 @@ module ActiveRecord
71
71
  # end
72
72
  #
73
73
  # Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
74
- # <tt>Shirt.red</tt> is not an Array; it resembles the association object
75
- # constructed by a +has_many+ declaration. For instance, you can invoke
76
- # <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
74
+ # <tt>Shirt.red</tt> is not an Array but an ActiveRecord::Relation,
75
+ # which is composable with other scopes; it resembles the association object
76
+ # constructed by a {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
77
+ # declaration. For instance, you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
77
78
  # <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
78
79
  # association objects, named \scopes act like an Array, implementing
79
80
  # Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
80
81
  # and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
81
- # <tt>Shirt.red</tt> really was an Array.
82
+ # <tt>Shirt.red</tt> really was an array.
82
83
  #
83
84
  # These named \scopes are composable. For instance,
84
85
  # <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
@@ -89,7 +90,8 @@ module ActiveRecord
89
90
  #
90
91
  # All scopes are available as class methods on the ActiveRecord::Base
91
92
  # descendant upon which the \scopes were defined. But they are also
92
- # available to +has_many+ associations. If,
93
+ # available to {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
94
+ # associations. If,
93
95
  #
94
96
  # class Person < ActiveRecord::Base
95
97
  # has_many :shirts
@@ -98,8 +100,8 @@ module ActiveRecord
98
100
  # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
99
101
  # Elton's red, dry clean only shirts.
100
102
  #
101
- # \Named scopes can also have extensions, just as with +has_many+
102
- # declarations:
103
+ # \Named scopes can also have extensions, just as with
104
+ # {has_many}[rdoc-ref:Associations::ClassMethods#has_many] declarations:
103
105
  #
104
106
  # class Shirt < ActiveRecord::Base
105
107
  # scope :red, -> { where(color: 'red') } do
@@ -149,13 +151,32 @@ module ActiveRecord
149
151
  "a class method with the same name."
150
152
  end
151
153
 
154
+ valid_scope_name?(name)
152
155
  extension = Module.new(&block) if block
153
156
 
154
- singleton_class.send(:define_method, name) do |*args|
155
- scope = all.scoping { body.call(*args) }
156
- scope = scope.extending(extension) if extension
157
+ if body.respond_to?(:to_proc)
158
+ singleton_class.send(:define_method, name) do |*args|
159
+ scope = all.scoping { instance_exec(*args, &body) }
160
+ scope = scope.extending(extension) if extension
161
+
162
+ scope || all
163
+ end
164
+ else
165
+ singleton_class.send(:define_method, name) do |*args|
166
+ scope = all.scoping { body.call(*args) }
167
+ scope = scope.extending(extension) if extension
168
+
169
+ scope || all
170
+ end
171
+ end
172
+ end
173
+
174
+ protected
157
175
 
158
- scope || all
176
+ def valid_scope_name?(name)
177
+ if respond_to?(name, true)
178
+ logger.warn "Creating scope :#{name}. " \
179
+ "Overwriting existing method #{self.name}.#{name}."
159
180
  end
160
181
  end
161
182
  end
@@ -0,0 +1,38 @@
1
+ module ActiveRecord
2
+ module SecureToken
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Example using #has_secure_token
7
+ #
8
+ # # Schema: User(token:string, auth_token:string)
9
+ # class User < ActiveRecord::Base
10
+ # has_secure_token
11
+ # has_secure_token :auth_token
12
+ # end
13
+ #
14
+ # user = User.new
15
+ # user.save
16
+ # user.token # => "pX27zsMN2ViQKta1bGfLmVJE"
17
+ # user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
18
+ # user.regenerate_token # => true
19
+ # user.regenerate_auth_token # => true
20
+ #
21
+ # <tt>SecureRandom::base58</tt> is used to generate the 24-character unique token, so collisions are highly unlikely.
22
+ #
23
+ # Note that it's still possible to generate a race condition in the database in the same way that
24
+ # {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
25
+ # You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
26
+ def has_secure_token(attribute = :token)
27
+ # Load securerandom only when has_secure_token is used.
28
+ require 'active_support/core_ext/securerandom'
29
+ define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
30
+ before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) unless self.send("#{attribute}?")}
31
+ end
32
+
33
+ def generate_unique_secure_token
34
+ SecureRandom.base58(24)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord #:nodoc:
2
- # = Active Record Serialization
2
+ # = Active Record \Serialization
3
3
  module Serialization
4
4
  extend ActiveSupport::Concern
5
5
  include ActiveModel::Serializers::JSON
@@ -11,12 +11,10 @@ module ActiveRecord #:nodoc:
11
11
  def serializable_hash(options = nil)
12
12
  options = options.try(:clone) || {}
13
13
 
14
- options[:except] = Array(options[:except]).map { |n| n.to_s }
14
+ options[:except] = Array(options[:except]).map(&:to_s)
15
15
  options[:except] |= Array(self.class.inheritance_column)
16
16
 
17
17
  super(options)
18
18
  end
19
19
  end
20
20
  end
21
-
22
- require 'active_record/serializers/xml_serializer'
@@ -7,12 +7,14 @@ module ActiveRecord
7
7
  # Book.where(name: "my book").where("author_id > 3")
8
8
  # end
9
9
  #
10
- # The cached statement is executed by using the +execute+ method:
10
+ # The cached statement is executed by using the
11
+ # [connection.execute]{rdoc-ref:ConnectionAdapters::DatabaseStatements#execute} method:
11
12
  #
12
13
  # cache.execute([], Book, Book.connection)
13
14
  #
14
- # The relation returned by the block is cached, and for each +execute+ call the cached relation gets duped.
15
- # Database is queried when +to_a+ is called on the relation.
15
+ # The relation returned by the block is cached, and for each
16
+ # [execute]{rdoc-ref:ConnectionAdapters::DatabaseStatements#execute}
17
+ # call the cached relation gets duped. Database is queried when +to_a+ is called on the relation.
16
18
  #
17
19
  # If you want to cache the statement without the values you can use the +bind+ method of the
18
20
  # block parameter.
@@ -47,8 +49,8 @@ module ActiveRecord
47
49
 
48
50
  def sql_for(binds, connection)
49
51
  val = @values.dup
50
- binds = binds.dup
51
- @indexes.each { |i| val[i] = connection.quote(*binds.shift.reverse) }
52
+ binds = connection.prepare_binds_for_database(binds)
53
+ @indexes.each { |i| val[i] = connection.quote(binds.shift) }
52
54
  val.join
53
55
  end
54
56
  end
@@ -67,21 +69,21 @@ module ActiveRecord
67
69
  end
68
70
 
69
71
  class BindMap # :nodoc:
70
- def initialize(bind_values)
72
+ def initialize(bound_attributes)
71
73
  @indexes = []
72
- @bind_values = bind_values
74
+ @bound_attributes = bound_attributes
73
75
 
74
- bind_values.each_with_index do |(_, value), i|
75
- if Substitute === value
76
+ bound_attributes.each_with_index do |attr, i|
77
+ if Substitute === attr.value
76
78
  @indexes << i
77
79
  end
78
80
  end
79
81
  end
80
82
 
81
83
  def bind(values)
82
- bvs = @bind_values.map { |pair| pair.dup }
83
- @indexes.each_with_index { |offset,i| bvs[offset][1] = values[i] }
84
- bvs
84
+ bas = @bound_attributes.dup
85
+ @indexes.each_with_index { |offset,i| bas[offset] = bas[offset].with_cast_value(values[i]) }
86
+ bas
85
87
  end
86
88
  end
87
89
 
@@ -89,7 +91,7 @@ module ActiveRecord
89
91
 
90
92
  def self.create(connection, block = Proc.new)
91
93
  relation = block.call Params.new
92
- bind_map = BindMap.new relation.bind_values
94
+ bind_map = BindMap.new relation.bound_attributes
93
95
  query_builder = connection.cacheable_query relation.arel
94
96
  new query_builder, bind_map
95
97
  end
@@ -104,7 +106,7 @@ module ActiveRecord
104
106
 
105
107
  sql = query_builder.sql_for bind_values, connection
106
108
 
107
- klass.find_by_sql sql, bind_values
109
+ klass.find_by_sql(sql, bind_values, preparable: true)
108
110
  end
109
111
  alias :call :execute
110
112
  end
@@ -15,11 +15,16 @@ module ActiveRecord
15
15
  # You can set custom coder to encode/decode your serialized attributes to/from different formats.
16
16
  # JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
17
17
  #
18
- # NOTE - If you are using PostgreSQL specific columns like +hstore+ or +json+ there is no need for
19
- # the serialization provided by +store+. Simply use +store_accessor+ instead to generate
18
+ # NOTE: If you are using PostgreSQL specific columns like +hstore+ or +json+ there is no need for
19
+ # the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
20
+ # Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
20
21
  # the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
21
22
  # using a symbol.
22
23
  #
24
+ # NOTE: The default validations with the exception of +uniqueness+ will work.
25
+ # For example, if you want to check for +uniqueness+ with +hstore+ you will
26
+ # need to use a custom validation to handle it.
27
+ #
23
28
  # Examples:
24
29
  #
25
30
  # class User < ActiveRecord::Base
@@ -39,7 +44,7 @@ module ActiveRecord
39
44
  # store_accessor :settings, :privileges, :servants
40
45
  # end
41
46
  #
42
- # The stored attribute names can be retrieved using +stored_attributes+.
47
+ # The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
43
48
  #
44
49
  # User.stored_attributes[:settings] # [:color, :homepage]
45
50
  #
@@ -0,0 +1,58 @@
1
+ module ActiveRecord
2
+ # ActiveRecord::Suppressor prevents the receiver from being saved during
3
+ # a given block.
4
+ #
5
+ # For example, here's a pattern of creating notifications when new comments
6
+ # are posted. (The notification may in turn trigger an email, a push
7
+ # notification, or just appear in the UI somewhere):
8
+ #
9
+ # class Comment < ActiveRecord::Base
10
+ # belongs_to :commentable, polymorphic: true
11
+ # after_create -> { Notification.create! comment: self,
12
+ # recipients: commentable.recipients }
13
+ # end
14
+ #
15
+ # That's what you want the bulk of the time. New comment creates a new
16
+ # Notification. But there may well be off cases, like copying a commentable
17
+ # and its comments, where you don't want that. So you'd have a concern
18
+ # something like this:
19
+ #
20
+ # module Copyable
21
+ # def copy_to(destination)
22
+ # Notification.suppress do
23
+ # # Copy logic that creates new comments that we do not want
24
+ # # triggering notifications.
25
+ # end
26
+ # end
27
+ # end
28
+ module Suppressor
29
+ extend ActiveSupport::Concern
30
+
31
+ module ClassMethods
32
+ def suppress(&block)
33
+ SuppressorRegistry.suppressed[name] = true
34
+ yield
35
+ ensure
36
+ SuppressorRegistry.suppressed[name] = false
37
+ end
38
+ end
39
+
40
+ def save(*) # :nodoc:
41
+ SuppressorRegistry.suppressed[self.class.name] ? true : super
42
+ end
43
+
44
+ def save!(*) # :nodoc:
45
+ SuppressorRegistry.suppressed[self.class.name] ? true : super
46
+ end
47
+ end
48
+
49
+ class SuppressorRegistry # :nodoc:
50
+ extend ActiveSupport::PerThreadRegistry
51
+
52
+ attr_reader :suppressed
53
+
54
+ def initialize
55
+ @suppressed = {}
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,68 @@
1
+ module ActiveRecord
2
+ class TableMetadata # :nodoc:
3
+ delegate :foreign_type, :foreign_key, to: :association, prefix: true
4
+ delegate :association_primary_key, to: :association
5
+
6
+ def initialize(klass, arel_table, association = nil)
7
+ @klass = klass
8
+ @arel_table = arel_table
9
+ @association = association
10
+ end
11
+
12
+ def resolve_column_aliases(hash)
13
+ # This method is a hot spot, so for now, use Hash[] to dup the hash.
14
+ # https://bugs.ruby-lang.org/issues/7166
15
+ new_hash = Hash[hash]
16
+ hash.each do |key, _|
17
+ if (key.is_a?(Symbol)) && klass.attribute_alias?(key)
18
+ new_hash[klass.attribute_alias(key)] = new_hash.delete(key)
19
+ end
20
+ end
21
+ new_hash
22
+ end
23
+
24
+ def arel_attribute(column_name)
25
+ if klass
26
+ klass.arel_attribute(column_name, arel_table)
27
+ else
28
+ arel_table[column_name]
29
+ end
30
+ end
31
+
32
+ def type(column_name)
33
+ if klass
34
+ klass.type_for_attribute(column_name.to_s)
35
+ else
36
+ Type::Value.new
37
+ end
38
+ end
39
+
40
+ def associated_with?(association_name)
41
+ klass && klass._reflect_on_association(association_name)
42
+ end
43
+
44
+ def associated_table(table_name)
45
+ return self if table_name == arel_table.name
46
+
47
+ association = klass._reflect_on_association(table_name)
48
+ if association && !association.polymorphic?
49
+ association_klass = association.klass
50
+ arel_table = association_klass.arel_table.alias(table_name)
51
+ else
52
+ type_caster = TypeCaster::Connection.new(klass, table_name)
53
+ association_klass = nil
54
+ arel_table = Arel::Table.new(table_name, type_caster: type_caster)
55
+ end
56
+
57
+ TableMetadata.new(association_klass, arel_table, association)
58
+ end
59
+
60
+ def polymorphic_association?
61
+ association && association.polymorphic?
62
+ end
63
+
64
+ protected
65
+
66
+ attr_reader :klass, :arel_table, :association
67
+ end
68
+ end
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  class DatabaseAlreadyExists < StandardError; end # :nodoc:
6
6
  class DatabaseNotSupported < StandardError; end # :nodoc:
7
7
 
8
- # <tt>ActiveRecord::Tasks::DatabaseTasks</tt> is a utility class, which encapsulates
8
+ # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
9
9
  # logic behind common tasks used to manage database and migrations.
10
10
  #
11
11
  # The tasks defined here are used with Rake tasks provided by Active Record.
@@ -18,15 +18,15 @@ module ActiveRecord
18
18
  #
19
19
  # The possible config values are:
20
20
  #
21
- # * +env+: current environment (like Rails.env).
22
- # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
23
- # * +db_dir+: your +db+ directory.
24
- # * +fixtures_path+: a path to fixtures directory.
25
- # * +migrations_paths+: a list of paths to directories with migrations.
26
- # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
27
- # * +root+: a path to the root of the application.
21
+ # * +env+: current environment (like Rails.env).
22
+ # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
23
+ # * +db_dir+: your +db+ directory.
24
+ # * +fixtures_path+: a path to fixtures directory.
25
+ # * +migrations_paths+: a list of paths to directories with migrations.
26
+ # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
27
+ # * +root+: a path to the root of the application.
28
28
  #
29
- # Example usage of +DatabaseTasks+ outside Rails could look as such:
29
+ # Example usage of DatabaseTasks outside Rails could look as such:
30
30
  #
31
31
  # include ActiveRecord::Tasks
32
32
  # DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
@@ -42,6 +42,22 @@ module ActiveRecord
42
42
 
43
43
  LOCAL_HOSTS = ['127.0.0.1', 'localhost']
44
44
 
45
+ def check_protected_environments!
46
+ unless ENV['DISABLE_DATABASE_ENVIRONMENT_CHECK']
47
+ current = ActiveRecord::Migrator.current_environment
48
+ stored = ActiveRecord::Migrator.last_stored_environment
49
+
50
+ if ActiveRecord::Migrator.protected_environment?
51
+ raise ActiveRecord::ProtectedEnvironmentError.new(stored)
52
+ end
53
+
54
+ if stored && stored != current
55
+ raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
56
+ end
57
+ end
58
+ rescue ActiveRecord::NoDatabaseError
59
+ end
60
+
45
61
  def register_task(pattern, task)
46
62
  @tasks ||= {}
47
63
  @tasks[pattern] = task
@@ -91,15 +107,21 @@ module ActiveRecord
91
107
  def create(*arguments)
92
108
  configuration = arguments.first
93
109
  class_for_adapter(configuration['adapter']).new(*arguments).create
110
+ $stdout.puts "Created database '#{configuration['database']}'"
94
111
  rescue DatabaseAlreadyExists
95
- $stderr.puts "#{configuration['database']} already exists"
112
+ $stderr.puts "Database '#{configuration['database']}' already exists"
96
113
  rescue Exception => error
97
- $stderr.puts error, *(error.backtrace)
114
+ $stderr.puts error
98
115
  $stderr.puts "Couldn't create database for #{configuration.inspect}"
116
+ raise
99
117
  end
100
118
 
101
119
  def create_all
120
+ old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
102
121
  each_local_configuration { |configuration| create configuration }
122
+ if old_pool
123
+ ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec)
124
+ end
103
125
  end
104
126
 
105
127
  def create_current(environment = env)
@@ -112,11 +134,13 @@ module ActiveRecord
112
134
  def drop(*arguments)
113
135
  configuration = arguments.first
114
136
  class_for_adapter(configuration['adapter']).new(*arguments).drop
137
+ $stdout.puts "Dropped database '#{configuration['database']}'"
115
138
  rescue ActiveRecord::NoDatabaseError
116
139
  $stderr.puts "Database '#{configuration['database']}' does not exist"
117
140
  rescue Exception => error
118
- $stderr.puts error, *(error.backtrace)
119
- $stderr.puts "Couldn't drop #{configuration['database']}"
141
+ $stderr.puts error
142
+ $stderr.puts "Couldn't drop database '#{configuration['database']}'"
143
+ raise
120
144
  end
121
145
 
122
146
  def drop_all
@@ -130,8 +154,6 @@ module ActiveRecord
130
154
  end
131
155
 
132
156
  def migrate
133
- raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
134
-
135
157
  verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
136
158
  version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
137
159
  scope = ENV['SCOPE']
@@ -191,27 +213,7 @@ module ActiveRecord
191
213
  class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
192
214
  end
193
215
 
194
- def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
195
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
196
- This method will act on a specific connection in the future.
197
- To act on the current connection, use `load_schema_current` instead.
198
- MSG
199
-
200
- load_schema_current(format, file)
201
- end
202
-
203
- def schema_file(format = ActiveRecord::Base.schema_format)
204
- case format
205
- when :ruby
206
- File.join(db_dir, "schema.rb")
207
- when :sql
208
- File.join(db_dir, "structure.sql")
209
- end
210
- end
211
-
212
- # This method is the successor of +load_schema+. We should rename it
213
- # after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
214
- def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
216
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
215
217
  file ||= schema_file(format)
216
218
 
217
219
  case format
@@ -225,24 +227,37 @@ module ActiveRecord
225
227
  else
226
228
  raise ArgumentError, "unknown format #{format.inspect}"
227
229
  end
230
+ ActiveRecord::InternalMetadata.create_table
231
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
228
232
  end
229
233
 
230
- def load_schema_current_if_exists(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
231
- if File.exist?(file || schema_file(format))
232
- load_schema_current(format, file, environment)
234
+ def load_schema_for(*args)
235
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
236
+ This method was renamed to `#load_schema` and will be removed in the future.
237
+ Use `#load_schema` instead.
238
+ MSG
239
+ load_schema(*args)
240
+ end
241
+
242
+ def schema_file(format = ActiveRecord::Base.schema_format)
243
+ case format
244
+ when :ruby
245
+ File.join(db_dir, "schema.rb")
246
+ when :sql
247
+ File.join(db_dir, "structure.sql")
233
248
  end
234
249
  end
235
250
 
236
251
  def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
237
252
  each_current_configuration(environment) { |configuration|
238
- load_schema_for configuration, format, file
253
+ load_schema configuration, format, file
239
254
  }
240
255
  ActiveRecord::Base.establish_connection(environment.to_sym)
241
256
  end
242
257
 
243
258
  def check_schema_file(filename)
244
259
  unless File.exist?(filename)
245
- message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.}
260
+ message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
246
261
  message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
247
262
  Kernel.abort message
248
263
  end
@@ -270,8 +285,7 @@ module ActiveRecord
270
285
 
271
286
  def each_current_configuration(environment)
272
287
  environments = [environment]
273
- # add test environment only if no RAILS_ENV was specified.
274
- environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
288
+ environments << 'test' if environment == 'development'
275
289
 
276
290
  configurations = ActiveRecord::Base.configurations.values_at(*environments)
277
291
  configurations.compact.each do |configuration|