activerecord 4.2.11.3 → 5.0.7.2

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

Potentially problematic release.


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

Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -51,11 +51,15 @@ module ActiveRecord
51
51
  end
52
52
 
53
53
  attrs = args.first
54
- if subclass_from_attributes?(attrs)
54
+ if has_attribute?(inheritance_column)
55
55
  subclass = subclass_from_attributes(attrs)
56
+
57
+ if subclass.nil? && base_class == self
58
+ subclass = subclass_from_attributes(column_defaults)
59
+ end
56
60
  end
57
61
 
58
- if subclass
62
+ if subclass && subclass != self
59
63
  subclass.new(*args, &block)
60
64
  else
61
65
  super
@@ -79,20 +83,10 @@ module ActiveRecord
79
83
  :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
80
84
  end
81
85
 
82
- def symbolized_base_class
83
- ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
84
- @symbolized_base_class ||= base_class.to_s.to_sym
85
- end
86
-
87
- def symbolized_sti_name
88
- ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
89
- @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
90
- end
91
-
92
86
  # Returns the class descending directly from ActiveRecord::Base, or
93
87
  # an abstract class, if any, in the inheritance hierarchy.
94
88
  #
95
- # If A extends AR::Base, A.base_class will return A. If B descends from A
89
+ # If A extends ActiveRecord::Base, A.base_class will return A. If B descends from A
96
90
  # through some arbitrarily deep hierarchy, B.base_class will return A.
97
91
  #
98
92
  # If B < A and C < B and if A is an abstract_class then both B.base_class
@@ -173,49 +167,47 @@ module ActiveRecord
173
167
  end
174
168
 
175
169
  def using_single_table_inheritance?(record)
176
- record[inheritance_column].present? && columns_hash.include?(inheritance_column)
170
+ record[inheritance_column].present? && has_attribute?(inheritance_column)
177
171
  end
178
172
 
179
173
  def find_sti_class(type_name)
180
- if store_full_sti_class
181
- ActiveSupport::Dependencies.constantize(type_name)
182
- else
183
- compute_type(type_name)
174
+ type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
175
+ subclass = begin
176
+ if store_full_sti_class
177
+ ActiveSupport::Dependencies.constantize(type_name)
178
+ else
179
+ compute_type(type_name)
180
+ end
181
+ rescue NameError
182
+ raise SubclassNotFound,
183
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
184
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
185
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
186
+ "or overwrite #{name}.inheritance_column to use another column for that information."
184
187
  end
185
- rescue NameError
186
- raise SubclassNotFound,
187
- "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
188
- "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
189
- "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
190
- "or overwrite #{name}.inheritance_column to use another column for that information."
188
+ unless subclass == self || descendants.include?(subclass)
189
+ raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
190
+ end
191
+ subclass
191
192
  end
192
193
 
193
194
  def type_condition(table = arel_table)
194
- sti_column = table[inheritance_column]
195
- sti_names = ([self] + descendants).map { |model| model.sti_name }
195
+ sti_column = arel_attribute(inheritance_column, table)
196
+ sti_names = ([self] + descendants).map(&:sti_name)
196
197
 
197
198
  sti_column.in(sti_names)
198
199
  end
199
200
 
200
201
  # Detect the subclass from the inheritance column of attrs. If the inheritance column value
201
202
  # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
202
- # If this is a StrongParameters hash, and access to inheritance_column is not permitted,
203
- # this will ignore the inheritance column and return nil
204
- def subclass_from_attributes?(attrs)
205
- columns_hash.include?(inheritance_column) && attrs.is_a?(Hash)
206
- end
207
-
208
203
  def subclass_from_attributes(attrs)
209
- subclass_name = attrs.with_indifferent_access[inheritance_column]
210
-
211
- if subclass_name.present? && subclass_name != self.name
212
- subclass = subclass_name.safe_constantize
204
+ attrs = attrs.to_h if attrs.respond_to?(:permitted?)
205
+ if attrs.is_a?(Hash)
206
+ subclass_name = attrs.with_indifferent_access[inheritance_column]
213
207
 
214
- unless descendants.include?(subclass)
215
- raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}")
208
+ if subclass_name.present?
209
+ find_sti_class(subclass_name)
216
210
  end
217
-
218
- subclass
219
211
  end
220
212
  end
221
213
  end
@@ -10,12 +10,12 @@ module ActiveRecord
10
10
  # Indicates the format used to generate the timestamp in the cache key.
11
11
  # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
12
12
  #
13
- # This is +:nsec+, by default.
13
+ # This is +:usec+, by default.
14
14
  class_attribute :cache_timestamp_format, :instance_writer => false
15
- self.cache_timestamp_format = :nsec
15
+ self.cache_timestamp_format = :usec
16
16
  end
17
17
 
18
- # Returns a String, which Action Pack uses for constructing an URL to this
18
+ # Returns a String, which Action Pack uses for constructing a URL to this
19
19
  # object. The default implementation returns this record's id as a String,
20
20
  # or nil if this record's unsaved.
21
21
  #
@@ -53,18 +53,21 @@ module ActiveRecord
53
53
  #
54
54
  # Person.find(5).cache_key(:updated_at, :last_reviewed_at)
55
55
  def cache_key(*timestamp_names)
56
- case
57
- when new_record?
56
+ if new_record?
58
57
  "#{model_name.cache_key}/new"
59
- when timestamp_names.any?
60
- timestamp = max_updated_column_timestamp(timestamp_names)
61
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
62
- "#{model_name.cache_key}/#{id}-#{timestamp}"
63
- when timestamp = max_updated_column_timestamp
64
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
65
- "#{model_name.cache_key}/#{id}-#{timestamp}"
66
58
  else
67
- "#{model_name.cache_key}/#{id}"
59
+ timestamp = if timestamp_names.any?
60
+ max_updated_column_timestamp(timestamp_names)
61
+ else
62
+ max_updated_column_timestamp
63
+ end
64
+
65
+ if timestamp
66
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
67
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
68
+ else
69
+ "#{model_name.cache_key}/#{id}"
70
+ end
68
71
  end
69
72
  end
70
73
 
@@ -84,7 +87,7 @@ module ActiveRecord
84
87
  # Values longer than 20 characters will be truncated. The value
85
88
  # is truncated word by word.
86
89
  #
87
- # user = User.find_by(name: 'David HeinemeierHansson')
90
+ # user = User.find_by(name: 'David Heinemeier Hansson')
88
91
  # user.id # => 125
89
92
  # user_path(user) # => "/users/125-david"
90
93
  #
@@ -0,0 +1,56 @@
1
+ require 'active_record/scoping/default'
2
+ require 'active_record/scoping/named'
3
+
4
+ module ActiveRecord
5
+ # This class is used to create a table that keeps track of values and keys such
6
+ # as which environment migrations were run in.
7
+ class InternalMetadata < ActiveRecord::Base # :nodoc:
8
+ class << self
9
+ def primary_key
10
+ "key"
11
+ end
12
+
13
+ def table_name
14
+ "#{table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{table_name_suffix}"
15
+ end
16
+
17
+ def original_table_name
18
+ "#{table_name_prefix}active_record_internal_metadatas#{table_name_suffix}"
19
+ end
20
+
21
+ def []=(key, value)
22
+ find_or_initialize_by(key: key).update_attributes!(value: value)
23
+ end
24
+
25
+ def [](key)
26
+ where(key: key).pluck(:value).first
27
+ end
28
+
29
+ def table_exists?
30
+ ActiveSupport::Deprecation.silence { connection.table_exists?(table_name) }
31
+ end
32
+
33
+ def original_table_exists?
34
+ # This method will be removed in Rails 5.1
35
+ # Since it is only necessary when `active_record_internal_metadatas` could exist
36
+ ActiveSupport::Deprecation.silence { connection.table_exists?(original_table_name) }
37
+ end
38
+
39
+ # Creates an internal metadata table with columns +key+ and +value+
40
+ def create_table
41
+ if original_table_exists?
42
+ connection.rename_table(original_table_name, table_name)
43
+ end
44
+ unless table_exists?
45
+ key_options = connection.internal_string_options_for_primary_key
46
+
47
+ connection.create_table(table_name, id: false) do |t|
48
+ t.string :key, key_options
49
+ t.string :value
50
+ t.timestamps
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -4,16 +4,32 @@ module ActiveRecord
4
4
  return coder unless coder.is_a?(Psych::Coder)
5
5
 
6
6
  case coder["active_record_yaml_version"]
7
- when 0 then coder
7
+ when 1 then coder
8
8
  else
9
9
  if coder["attributes"].is_a?(AttributeSet)
10
- coder
10
+ Rails420.convert(klass, coder)
11
11
  else
12
12
  Rails41.convert(klass, coder)
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
+ module Rails420
18
+ def self.convert(klass, coder)
19
+ attribute_set = coder["attributes"]
20
+
21
+ klass.attribute_names.each do |attr_name|
22
+ attribute = attribute_set[attr_name]
23
+ if attribute.type.is_a?(Delegator)
24
+ type_from_klass = klass.type_for_attribute(attr_name)
25
+ attribute_set[attr_name] = attribute.with_type(type_from_klass)
26
+ end
27
+ end
28
+
29
+ coder
30
+ end
31
+ end
32
+
17
33
  module Rails41
18
34
  def self.convert(klass, coder)
19
35
  attributes = klass.attributes_builder
@@ -7,6 +7,7 @@ en:
7
7
  # Default error messages
8
8
  errors:
9
9
  messages:
10
+ required: "must exist"
10
11
  taken: "has already been taken"
11
12
 
12
13
  # Active Record models configuration
@@ -15,8 +16,8 @@ en:
15
16
  messages:
16
17
  record_invalid: "Validation failed: %{errors}"
17
18
  restrict_dependent_destroy:
18
- one: "Cannot delete record because a dependent %{record} exists"
19
- many: "Cannot delete record because dependent %{record} exist"
19
+ has_one: "Cannot delete record because a dependent %{record} exists"
20
+ has_many: "Cannot delete record because dependent %{record} exist"
20
21
  # Append your own errors here or at the model/attributes scope.
21
22
 
22
23
  # You can define own errors for models or model attributes.
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  #
12
12
  # == Usage
13
13
  #
14
- # Active Records support optimistic locking if the field +lock_version+ is present. Each update to the
14
+ # Active Record supports optimistic locking if the +lock_version+ field is present. Each update to the
15
15
  # record increments the +lock_version+ column and the locking facilities ensure that records instantiated twice
16
16
  # will let the last one saved raise a +StaleObjectError+ if the first was also updated. Example:
17
17
  #
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  # p1.save
23
23
  #
24
24
  # p2.first_name = "should fail"
25
- # p2.save # Raises a ActiveRecord::StaleObjectError
25
+ # p2.save # Raises an ActiveRecord::StaleObjectError
26
26
  #
27
27
  # Optimistic locking will also check for stale data when objects are destroyed. Example:
28
28
  #
@@ -32,7 +32,7 @@ module ActiveRecord
32
32
  # p1.first_name = "Michael"
33
33
  # p1.save
34
34
  #
35
- # p2.destroy # Raises a ActiveRecord::StaleObjectError
35
+ # p2.destroy # Raises an ActiveRecord::StaleObjectError
36
36
  #
37
37
  # You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
38
38
  # or otherwise apply the business logic needed to resolve the conflict.
@@ -93,9 +93,9 @@ module ActiveRecord
93
93
  self.class.primary_key => id,
94
94
  lock_col => previous_lock_value,
95
95
  ).update_all(
96
- Hash[attributes_for_update(attribute_names).map do |name|
96
+ attributes_for_update(attribute_names).map do |name|
97
97
  [name, _read_attribute(name)]
98
- end]
98
+ end.to_h
99
99
  )
100
100
 
101
101
  unless affected_rows == 1
@@ -125,12 +125,8 @@ module ActiveRecord
125
125
  relation = super
126
126
 
127
127
  if locking_enabled?
128
- column_name = self.class.locking_column
129
- column = self.class.columns_hash[column_name]
130
- substitute = self.class.connection.substitute_at(column)
131
-
132
- relation = relation.where(self.class.arel_table[column_name].eq(substitute))
133
- relation.bind_values << [column, self[column_name].to_i]
128
+ locking_column = self.class.locking_column
129
+ relation = relation.where(locking_column => _read_attribute(locking_column))
134
130
  end
135
131
 
136
132
  relation
@@ -148,13 +144,13 @@ module ActiveRecord
148
144
 
149
145
  # Set the column to use for optimistic locking. Defaults to +lock_version+.
150
146
  def locking_column=(value)
151
- clear_caches_calculated_from_columns
147
+ reload_schema_from_cache
152
148
  @locking_column = value.to_s
153
149
  end
154
150
 
155
151
  # The version column used for optimistic locking. Defaults to +lock_version+.
156
152
  def locking_column
157
- reset_locking_column unless defined?(@locking_column)
153
+ @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
158
154
  @locking_column
159
155
  end
160
156
 
@@ -188,12 +184,16 @@ module ActiveRecord
188
184
  end
189
185
  end
190
186
 
191
- class LockingType < SimpleDelegator # :nodoc:
192
- def type_cast_from_database(value)
187
+ class LockingType < DelegateClass(Type::Value) # :nodoc:
188
+ def deserialize(value)
193
189
  # `nil` *should* be changed to 0
194
190
  super.to_i
195
191
  end
196
192
 
193
+ def serialize(value)
194
+ super.to_i
195
+ end
196
+
197
197
  def init_with(coder)
198
198
  __setobj__(coder['subtype'])
199
199
  end
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
  # end
52
52
  #
53
53
  # Database-specific information on row locking:
54
- # MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
54
+ # MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
55
55
  # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
56
56
  module Pessimistic
57
57
  # Obtain a row lock on this record. Reloads the record to obtain the requested
@@ -20,20 +20,6 @@ module ActiveRecord
20
20
  @odd = false
21
21
  end
22
22
 
23
- def render_bind(column, value)
24
- if column
25
- if column.binary?
26
- # This specifically deals with the PG adapter that casts bytea columns into a Hash.
27
- value = value[:value] if value.is_a?(Hash)
28
- value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
29
- end
30
-
31
- [column.name, value]
32
- else
33
- [nil, value]
34
- end
35
- end
36
-
37
23
  def sql(event)
38
24
  self.class.runtime += event.duration
39
25
  return unless logger.debug?
@@ -47,23 +33,61 @@ module ActiveRecord
47
33
  binds = nil
48
34
 
49
35
  unless (payload[:binds] || []).empty?
50
- binds = " " + payload[:binds].map { |col,v|
51
- render_bind(col, v)
36
+ casted_params = type_casted_binds(payload[:type_casted_binds])
37
+ binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
38
+ render_bind(attr, value)
52
39
  }.inspect
53
40
  end
54
41
 
55
- if odd?
56
- name = color(name, CYAN, true)
57
- sql = color(sql, nil, true)
58
- else
59
- name = color(name, MAGENTA, true)
60
- end
42
+ name = colorize_payload_name(name, payload[:name])
43
+ sql = color(sql, sql_color(sql), true)
61
44
 
62
45
  debug " #{name} #{sql}#{binds}"
63
46
  end
64
47
 
65
- def odd?
66
- @odd = !@odd
48
+ private
49
+
50
+ def type_casted_binds(casted_binds)
51
+ casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
52
+ end
53
+
54
+ def render_bind(attr, value)
55
+ if attr.is_a?(Array)
56
+ attr = attr.first
57
+ elsif attr.type.binary? && attr.value
58
+ value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
59
+ end
60
+
61
+ [attr && attr.name, value]
62
+ end
63
+
64
+ def colorize_payload_name(name, payload_name)
65
+ if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
66
+ color(name, MAGENTA, true)
67
+ else
68
+ color(name, CYAN, true)
69
+ end
70
+ end
71
+
72
+ def sql_color(sql)
73
+ case sql
74
+ when /\A\s*rollback/mi
75
+ RED
76
+ when /select .*for update/mi, /\A\s*lock/mi
77
+ WHITE
78
+ when /\A\s*select/i
79
+ BLUE
80
+ when /\A\s*insert/i
81
+ GREEN
82
+ when /\A\s*update/i
83
+ YELLOW
84
+ when /\A\s*delete/i
85
+ RED
86
+ when /transaction\s*\Z/i
87
+ CYAN
88
+ else
89
+ MAGENTA
90
+ end
67
91
  end
68
92
 
69
93
  def logger