activerecord 4.1.0 → 4.2.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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +776 -1330
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/association_relation.rb +4 -0
  6. data/lib/active_record/associations/alias_tracker.rb +14 -13
  7. data/lib/active_record/associations/association.rb +2 -2
  8. data/lib/active_record/associations/association_scope.rb +83 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +15 -4
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
  13. data/lib/active_record/associations/builder/has_many.rb +1 -1
  14. data/lib/active_record/associations/builder/has_one.rb +2 -2
  15. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  16. data/lib/active_record/associations/collection_association.rb +66 -29
  17. data/lib/active_record/associations/collection_proxy.rb +22 -26
  18. data/lib/active_record/associations/has_many_association.rb +65 -18
  19. data/lib/active_record/associations/has_many_through_association.rb +55 -27
  20. data/lib/active_record/associations/has_one_association.rb +0 -1
  21. data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
  22. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  23. data/lib/active_record/associations/join_dependency.rb +20 -12
  24. data/lib/active_record/associations/preloader/association.rb +34 -11
  25. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  26. data/lib/active_record/associations/preloader.rb +49 -59
  27. data/lib/active_record/associations/singular_association.rb +25 -4
  28. data/lib/active_record/associations/through_association.rb +23 -14
  29. data/lib/active_record/associations.rb +171 -42
  30. data/lib/active_record/attribute.rb +149 -0
  31. data/lib/active_record/attribute_assignment.rb +18 -10
  32. data/lib/active_record/attribute_decorators.rb +66 -0
  33. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  34. data/lib/active_record/attribute_methods/dirty.rb +98 -44
  35. data/lib/active_record/attribute_methods/primary_key.rb +14 -8
  36. data/lib/active_record/attribute_methods/query.rb +1 -1
  37. data/lib/active_record/attribute_methods/read.rb +22 -59
  38. data/lib/active_record/attribute_methods/serialization.rb +37 -147
  39. data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
  40. data/lib/active_record/attribute_methods/write.rb +14 -21
  41. data/lib/active_record/attribute_methods.rb +67 -94
  42. data/lib/active_record/attribute_set/builder.rb +86 -0
  43. data/lib/active_record/attribute_set.rb +77 -0
  44. data/lib/active_record/attributes.rb +139 -0
  45. data/lib/active_record/autosave_association.rb +45 -38
  46. data/lib/active_record/base.rb +10 -20
  47. data/lib/active_record/callbacks.rb +7 -7
  48. data/lib/active_record/coders/json.rb +13 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
  60. data/lib/active_record/connection_adapters/column.rb +28 -239
  61. data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
  62. data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
  63. data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
  64. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  65. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
  67. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  96. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
  97. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  98. data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
  99. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  100. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
  101. data/lib/active_record/connection_handling.rb +3 -3
  102. data/lib/active_record/core.rb +143 -32
  103. data/lib/active_record/counter_cache.rb +60 -7
  104. data/lib/active_record/enum.rb +10 -11
  105. data/lib/active_record/errors.rb +49 -27
  106. data/lib/active_record/explain.rb +1 -1
  107. data/lib/active_record/fixtures.rb +56 -70
  108. data/lib/active_record/gem_version.rb +2 -2
  109. data/lib/active_record/inheritance.rb +35 -10
  110. data/lib/active_record/integration.rb +4 -4
  111. data/lib/active_record/locking/optimistic.rb +35 -17
  112. data/lib/active_record/log_subscriber.rb +1 -1
  113. data/lib/active_record/migration/command_recorder.rb +19 -2
  114. data/lib/active_record/migration/join_table.rb +1 -1
  115. data/lib/active_record/migration.rb +52 -49
  116. data/lib/active_record/model_schema.rb +49 -57
  117. data/lib/active_record/nested_attributes.rb +7 -7
  118. data/lib/active_record/null_relation.rb +19 -5
  119. data/lib/active_record/persistence.rb +50 -31
  120. data/lib/active_record/query_cache.rb +3 -3
  121. data/lib/active_record/querying.rb +10 -7
  122. data/lib/active_record/railtie.rb +14 -11
  123. data/lib/active_record/railties/databases.rake +56 -54
  124. data/lib/active_record/readonly_attributes.rb +0 -1
  125. data/lib/active_record/reflection.rb +286 -102
  126. data/lib/active_record/relation/batches.rb +0 -1
  127. data/lib/active_record/relation/calculations.rb +39 -31
  128. data/lib/active_record/relation/delegation.rb +2 -2
  129. data/lib/active_record/relation/finder_methods.rb +80 -36
  130. data/lib/active_record/relation/merger.rb +25 -30
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
  132. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  133. data/lib/active_record/relation/predicate_builder.rb +11 -10
  134. data/lib/active_record/relation/query_methods.rb +141 -55
  135. data/lib/active_record/relation/spawn_methods.rb +3 -0
  136. data/lib/active_record/relation.rb +69 -30
  137. data/lib/active_record/result.rb +18 -7
  138. data/lib/active_record/sanitization.rb +12 -2
  139. data/lib/active_record/schema.rb +0 -1
  140. data/lib/active_record/schema_dumper.rb +58 -26
  141. data/lib/active_record/schema_migration.rb +11 -0
  142. data/lib/active_record/scoping/default.rb +8 -7
  143. data/lib/active_record/scoping/named.rb +4 -0
  144. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  145. data/lib/active_record/statement_cache.rb +95 -10
  146. data/lib/active_record/store.rb +19 -10
  147. data/lib/active_record/tasks/database_tasks.rb +73 -7
  148. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
  149. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  150. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  151. data/lib/active_record/timestamp.rb +11 -9
  152. data/lib/active_record/transactions.rb +37 -21
  153. data/lib/active_record/type/big_integer.rb +13 -0
  154. data/lib/active_record/type/binary.rb +50 -0
  155. data/lib/active_record/type/boolean.rb +30 -0
  156. data/lib/active_record/type/date.rb +46 -0
  157. data/lib/active_record/type/date_time.rb +43 -0
  158. data/lib/active_record/type/decimal.rb +40 -0
  159. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  160. data/lib/active_record/type/decorator.rb +14 -0
  161. data/lib/active_record/type/float.rb +19 -0
  162. data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
  163. data/lib/active_record/type/integer.rb +55 -0
  164. data/lib/active_record/type/mutable.rb +16 -0
  165. data/lib/active_record/type/numeric.rb +36 -0
  166. data/lib/active_record/type/serialized.rb +56 -0
  167. data/lib/active_record/type/string.rb +36 -0
  168. data/lib/active_record/type/text.rb +11 -0
  169. data/lib/active_record/type/time.rb +26 -0
  170. data/lib/active_record/type/time_value.rb +38 -0
  171. data/lib/active_record/type/type_map.rb +64 -0
  172. data/lib/active_record/type/unsigned_integer.rb +15 -0
  173. data/lib/active_record/type/value.rb +101 -0
  174. data/lib/active_record/type.rb +23 -0
  175. data/lib/active_record/validations/associated.rb +5 -3
  176. data/lib/active_record/validations/presence.rb +6 -4
  177. data/lib/active_record/validations/uniqueness.rb +11 -17
  178. data/lib/active_record/validations.rb +25 -19
  179. data/lib/active_record.rb +3 -0
  180. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  181. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
  182. data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +65 -10
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,6 +1,37 @@
1
1
  require 'active_support/core_ext/hash/indifferent_access'
2
2
 
3
3
  module ActiveRecord
4
+ # == Single table inheritance
5
+ #
6
+ # Active Record allows inheritance by storing the name of the class in a column that by
7
+ # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
8
+ # This means that an inheritance looking like this:
9
+ #
10
+ # class Company < ActiveRecord::Base; end
11
+ # class Firm < Company; end
12
+ # class Client < Company; end
13
+ # class PriorityClient < Client; end
14
+ #
15
+ # When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
16
+ # the companies table with type = "Firm". You can then fetch this row again using
17
+ # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
18
+ #
19
+ # Be aware that because the type column is an attribute on the record every new
20
+ # subclass will instantly be marked as dirty and the type column will be included
21
+ # in the list of changed attributes on the record. This is different from non
22
+ # STI classes:
23
+ #
24
+ # Company.new.changed? # => false
25
+ # Firm.new.changed? # => true
26
+ # Firm.new.changes # => {"type"=>["","Firm"]}
27
+ #
28
+ # If you don't have a type column defined in your table, single-table inheritance won't
29
+ # be triggered. In that case, it'll work just like normal subclasses with no special magic
30
+ # for differentiating between them or reloading the right type with find.
31
+ #
32
+ # Note, all the attributes for all the cases are kept in the same table. Read more:
33
+ # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
34
+ #
4
35
  module Inheritance
5
36
  extend ActiveSupport::Concern
6
37
 
@@ -49,12 +80,12 @@ module ActiveRecord
49
80
  end
50
81
 
51
82
  def symbolized_base_class
52
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_base_class is deprecated and will be removed without replacement.")
83
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
53
84
  @symbolized_base_class ||= base_class.to_s.to_sym
54
85
  end
55
86
 
56
87
  def symbolized_sti_name
57
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_sti_name is deprecated and will be removed without replacement.")
88
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
58
89
  @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
59
90
  end
60
91
 
@@ -120,14 +151,8 @@ module ActiveRecord
120
151
  candidates << type_name
121
152
 
122
153
  candidates.each do |candidate|
123
- begin
124
- constant = ActiveSupport::Dependencies.constantize(candidate)
125
- return constant if candidate == constant.to_s
126
- # We don't want to swallow NoMethodError < NameError errors
127
- rescue NoMethodError
128
- raise
129
- rescue NameError
130
- end
154
+ constant = ActiveSupport::Dependencies.safe_constantize(candidate)
155
+ return constant if candidate == constant.to_s
131
156
  end
132
157
 
133
158
  raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
@@ -55,16 +55,16 @@ module ActiveRecord
55
55
  def cache_key(*timestamp_names)
56
56
  case
57
57
  when new_record?
58
- "#{self.class.model_name.cache_key}/new"
58
+ "#{model_name.cache_key}/new"
59
59
  when timestamp_names.any?
60
60
  timestamp = max_updated_column_timestamp(timestamp_names)
61
61
  timestamp = timestamp.utc.to_s(cache_timestamp_format)
62
- "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
62
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
63
63
  when timestamp = max_updated_column_timestamp
64
64
  timestamp = timestamp.utc.to_s(cache_timestamp_format)
65
- "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
65
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
66
66
  else
67
- "#{self.class.model_name.cache_key}/#{id}"
67
+ "#{model_name.cache_key}/#{id}"
68
68
  end
69
69
  end
70
70
 
@@ -66,7 +66,7 @@ module ActiveRecord
66
66
  send(lock_col + '=', previous_lock_value + 1)
67
67
  end
68
68
 
69
- def update_record(attribute_names = @attributes.keys) #:nodoc:
69
+ def _update_record(attribute_names = self.attribute_names) #:nodoc:
70
70
  return super unless locking_enabled?
71
71
  return 0 if attribute_names.empty?
72
72
 
@@ -120,7 +120,7 @@ module ActiveRecord
120
120
  if locking_enabled?
121
121
  column_name = self.class.locking_column
122
122
  column = self.class.columns_hash[column_name]
123
- substitute = self.class.connection.substitute_at(column, relation.bind_values.length)
123
+ substitute = self.class.connection.substitute_at(column)
124
124
 
125
125
  relation = relation.where(self.class.arel_table[column_name].eq(substitute))
126
126
  relation.bind_values << [column, self[column_name].to_i]
@@ -141,7 +141,7 @@ module ActiveRecord
141
141
 
142
142
  # Set the column to use for optimistic locking. Defaults to +lock_version+.
143
143
  def locking_column=(value)
144
- @column_defaults = nil
144
+ clear_caches_calculated_from_columns
145
145
  @locking_column = value.to_s
146
146
  end
147
147
 
@@ -151,12 +151,6 @@ module ActiveRecord
151
151
  @locking_column
152
152
  end
153
153
 
154
- # Quote the column name used for optimistic locking.
155
- def quoted_locking_column
156
- ActiveSupport::Deprecation.warn "ActiveRecord::Base.quoted_locking_column is deprecated and will be removed in Rails 4.2 or later."
157
- connection.quote_column_name(locking_column)
158
- end
159
-
160
154
  # Reset the column used for optimistic locking back to the +lock_version+ default.
161
155
  def reset_locking_column
162
156
  self.locking_column = DEFAULT_LOCKING_COLUMN
@@ -169,18 +163,42 @@ module ActiveRecord
169
163
  super
170
164
  end
171
165
 
172
- def column_defaults
173
- @column_defaults ||= begin
174
- defaults = super
175
-
176
- if defaults.key?(locking_column) && lock_optimistically
177
- defaults[locking_column] ||= 0
166
+ private
167
+
168
+ # We need to apply this decorator here, rather than on module inclusion. The closure
169
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
170
+ # sub class being decorated. As such, changes to `lock_optimistically`, or
171
+ # `locking_column` would not be picked up.
172
+ def inherited(subclass)
173
+ subclass.class_eval do
174
+ is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
175
+ decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
176
+ LockingType.new(type)
178
177
  end
179
-
180
- defaults
181
178
  end
179
+ super
182
180
  end
183
181
  end
184
182
  end
183
+
184
+ class LockingType < SimpleDelegator # :nodoc:
185
+ def type_cast_from_database(value)
186
+ # `nil` *should* be changed to 0
187
+ super.to_i
188
+ end
189
+
190
+ def changed?(old_value, *)
191
+ # Ensure we save if the default was `nil`
192
+ super || old_value == 0
193
+ end
194
+
195
+ def init_with(coder)
196
+ __setobj__(coder['subtype'])
197
+ end
198
+
199
+ def encode_with(coder)
200
+ coder['subtype'] = __getobj__
201
+ end
202
+ end
185
203
  end
186
204
  end
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
  if column.binary?
26
26
  # This specifically deals with the PG adapter that casts bytea columns into a Hash.
27
27
  value = value[:value] if value.is_a?(Hash)
28
- value = "<#{value.bytesize} bytes of binary data>"
28
+ value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
29
29
  end
30
30
 
31
31
  [column.name, value]
@@ -74,7 +74,9 @@ module ActiveRecord
74
74
  :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
75
75
  :change_column_default, :add_reference, :remove_reference, :transaction,
76
76
  :drop_join_table, :drop_table, :execute_block, :enable_extension,
77
- :change_column, :execute, :remove_columns, :change_column_null # irreversible methods need to be here too
77
+ :change_column, :execute, :remove_columns, :change_column_null,
78
+ :add_foreign_key, :remove_foreign_key
79
+ # irreversible methods need to be here too
78
80
  ].each do |method|
79
81
  class_eval <<-EOV, __FILE__, __LINE__ + 1
80
82
  def #{method}(*args, &block) # def create_table(*args, &block)
@@ -85,7 +87,7 @@ module ActiveRecord
85
87
  alias :add_belongs_to :add_reference
86
88
  alias :remove_belongs_to :remove_reference
87
89
 
88
- def change_table(table_name, options = {})
90
+ def change_table(table_name, options = {}) # :nodoc:
89
91
  yield delegate.update_table_definition(table_name, self)
90
92
  end
91
93
 
@@ -167,6 +169,21 @@ module ActiveRecord
167
169
  [:change_column_null, args]
168
170
  end
169
171
 
172
+ def invert_add_foreign_key(args)
173
+ from_table, to_table, add_options = args
174
+ add_options ||= {}
175
+
176
+ if add_options[:name]
177
+ options = { name: add_options[:name] }
178
+ elsif add_options[:column]
179
+ options = { column: add_options[:column] }
180
+ else
181
+ options = to_table
182
+ end
183
+
184
+ [:remove_foreign_key, [from_table, options]]
185
+ end
186
+
170
187
  # Forwards any missing method call to the \target.
171
188
  def method_missing(method, *args, &block)
172
189
  if @delegate.respond_to?(method)
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  end
9
9
 
10
10
  def join_table_name(table_1, table_2)
11
- [table_1.to_s, table_2.to_s].sort.join("_").to_sym
11
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
12
12
  end
13
13
  end
14
14
  end
@@ -161,21 +161,14 @@ module ActiveRecord
161
161
  # in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
162
162
  # UTC formatted date and time that the migration was generated.
163
163
  #
164
- # You may then edit the <tt>up</tt> and <tt>down</tt> methods of
165
- # MyNewMigration.
166
- #
167
164
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
168
165
  #
169
166
  # rails generate migration add_fieldname_to_tablename fieldname:string
170
167
  #
171
168
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
172
169
  # class AddFieldnameToTablename < ActiveRecord::Migration
173
- # def up
174
- # add_column :tablenames, :fieldname, :string
175
- # end
176
- #
177
- # def down
178
- # remove_column :tablenames, :fieldname
170
+ # def change
171
+ # add_column :tablenames, :field, :string
179
172
  # end
180
173
  # end
181
174
  #
@@ -188,14 +181,17 @@ module ActiveRecord
188
181
  #
189
182
  # To roll the database back to a previous migration version, use
190
183
  # <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
191
- # you wish to downgrade. If any of the migrations throw an
192
- # <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
193
- # have some manual work to do.
184
+ # you wish to downgrade. Alternatively, you can also use the STEP option if you
185
+ # wish to rollback last few migrations. <tt>rake db:migrate STEP=2</tt> will rollback
186
+ # the latest two migrations.
187
+ #
188
+ # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
189
+ # that step will fail and you'll have some manual work to do.
194
190
  #
195
191
  # == Database support
196
192
  #
197
193
  # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
198
- # SQL Server, Sybase, and Oracle (all supported databases except DB2).
194
+ # SQL Server, and Oracle (all supported databases except DB2).
199
195
  #
200
196
  # == More examples
201
197
  #
@@ -372,13 +368,21 @@ module ActiveRecord
372
368
  end
373
369
 
374
370
  def call(env)
375
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
376
- if @last_check < mtime
377
- ActiveRecord::Migration.check_pending!
378
- @last_check = mtime
371
+ if connection.supports_migrations?
372
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
373
+ if @last_check < mtime
374
+ ActiveRecord::Migration.check_pending!(connection)
375
+ @last_check = mtime
376
+ end
379
377
  end
380
378
  @app.call(env)
381
379
  end
380
+
381
+ private
382
+
383
+ def connection
384
+ ActiveRecord::Base.connection
385
+ end
382
386
  end
383
387
 
384
388
  class << self
@@ -390,8 +394,15 @@ module ActiveRecord
390
394
  end
391
395
 
392
396
  def load_schema_if_pending!
393
- if ActiveRecord::Migrator.needs_migration?
394
- ActiveRecord::Tasks::DatabaseTasks.load_schema
397
+ if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
398
+ # Roundrip to Rake to allow plugins to hook into database initialization.
399
+ FileUtils.cd Rails.root do
400
+ current_config = Base.connection_config
401
+ Base.clear_all_connections!
402
+ system("bin/rake db:test:prepare")
403
+ # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
404
+ Base.establish_connection(current_config)
405
+ end
395
406
  check_pending!
396
407
  end
397
408
  end
@@ -640,9 +651,11 @@ module ActiveRecord
640
651
 
641
652
  say_with_time "#{method}(#{arg_list})" do
642
653
  unless @connection.respond_to? :revert
643
- unless arguments.empty? || method == :execute
654
+ unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
644
655
  arguments[0] = proper_table_name(arguments.first, table_name_options)
645
- arguments[1] = proper_table_name(arguments.second, table_name_options) if method == :rename_table
656
+ if [:rename_table, :add_foreign_key].include?(method)
657
+ arguments[1] = proper_table_name(arguments.second, table_name_options)
658
+ end
646
659
  end
647
660
  end
648
661
  return super unless connection.respond_to?(method)
@@ -711,7 +724,7 @@ module ActiveRecord
711
724
  if ActiveRecord::Base.timestamped_migrations
712
725
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
713
726
  else
714
- "%.3d" % number
727
+ SchemaMigration.normalize_migration_number(number)
715
728
  end
716
729
  end
717
730
 
@@ -804,43 +817,46 @@ module ActiveRecord
804
817
  migrations = migrations(migrations_paths)
805
818
  migrations.select! { |m| yield m } if block_given?
806
819
 
807
- self.new(:up, migrations, target_version).migrate
820
+ new(:up, migrations, target_version).migrate
808
821
  end
809
822
 
810
823
  def down(migrations_paths, target_version = nil, &block)
811
824
  migrations = migrations(migrations_paths)
812
825
  migrations.select! { |m| yield m } if block_given?
813
826
 
814
- self.new(:down, migrations, target_version).migrate
827
+ new(:down, migrations, target_version).migrate
815
828
  end
816
829
 
817
830
  def run(direction, migrations_paths, target_version)
818
- self.new(direction, migrations(migrations_paths), target_version).run
831
+ new(direction, migrations(migrations_paths), target_version).run
819
832
  end
820
833
 
821
834
  def open(migrations_paths)
822
- self.new(:up, migrations(migrations_paths), nil)
835
+ new(:up, migrations(migrations_paths), nil)
823
836
  end
824
837
 
825
838
  def schema_migrations_table_name
826
839
  SchemaMigration.table_name
827
840
  end
828
841
 
829
- def get_all_versions
830
- SchemaMigration.all.map { |x| x.version.to_i }.sort
842
+ def get_all_versions(connection = Base.connection)
843
+ if connection.table_exists?(schema_migrations_table_name)
844
+ SchemaMigration.all.map { |x| x.version.to_i }.sort
845
+ else
846
+ []
847
+ end
831
848
  end
832
849
 
833
850
  def current_version(connection = Base.connection)
834
- sm_table = schema_migrations_table_name
835
- if connection.table_exists?(sm_table)
836
- get_all_versions.max || 0
837
- else
838
- 0
839
- end
851
+ get_all_versions(connection).max || 0
840
852
  end
841
853
 
842
854
  def needs_migration?(connection = Base.connection)
843
- current_version(connection) < last_version
855
+ (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
856
+ end
857
+
858
+ def any_migrations?
859
+ migrations(migrations_paths).any?
844
860
  end
845
861
 
846
862
  def last_version
@@ -851,19 +867,6 @@ module ActiveRecord
851
867
  migrations(migrations_paths).last || NullMigration.new
852
868
  end
853
869
 
854
- def proper_table_name(name, options = {})
855
- ActiveSupport::Deprecation.warn "ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.2. Use the proper_table_name instance method on ActiveRecord::Migration instead"
856
- options = {
857
- table_name_prefix: ActiveRecord::Base.table_name_prefix,
858
- table_name_suffix: ActiveRecord::Base.table_name_suffix
859
- }.merge(options)
860
- if name.respond_to? :table_name
861
- name.table_name
862
- else
863
- "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
864
- end
865
- end
866
-
867
870
  def migrations_paths
868
871
  @migrations_paths ||= ['db/migrate']
869
872
  # just to not break things if someone uses: migration_path = some_string
@@ -895,7 +898,7 @@ module ActiveRecord
895
898
  private
896
899
 
897
900
  def move(direction, migrations_paths, steps)
898
- migrator = self.new(direction, migrations(migrations_paths))
901
+ migrator = new(direction, migrations(migrations_paths))
899
902
  start_index = migrator.migrations.index(migrator.current_migration)
900
903
 
901
904
  if start_index
@@ -29,6 +29,10 @@ module ActiveRecord
29
29
  # :singleton-method:
30
30
  # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
31
31
  # "people_basecamp"). By default, the suffix is the empty string.
32
+ #
33
+ # If you are organising your models within modules, you can add a suffix to the models within
34
+ # a namespace by defining a singleton method in the parent module called table_name_suffix which
35
+ # returns your chosen suffix.
32
36
  class_attribute :table_name_suffix, instance_writer: false
33
37
  self.table_name_suffix = ""
34
38
 
@@ -47,6 +51,19 @@ module ActiveRecord
47
51
  self.pluralize_table_names = true
48
52
 
49
53
  self.inheritance_column = 'type'
54
+
55
+ delegate :type_for_attribute, to: :class
56
+ end
57
+
58
+ # Derives the join table name for +first_table+ and +second_table+. The
59
+ # table names appear in alphabetical order. A common prefix is removed
60
+ # (useful for namespaced models like Music::Artist and Music::Record):
61
+ #
62
+ # artists, records => artists_records
63
+ # records, artists => artists_records
64
+ # music_artists, music_records => music_artists_records
65
+ def self.derive_join_table_name(first_table, second_table) # :nodoc:
66
+ [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
50
67
  end
51
68
 
52
69
  module ClassMethods
@@ -153,6 +170,10 @@ module ActiveRecord
153
170
  (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
154
171
  end
155
172
 
173
+ def full_table_name_suffix #:nodoc:
174
+ (parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
175
+ end
176
+
156
177
  # Defines the name of the table column which will store the class name on single-table
157
178
  # inheritance situations.
158
179
  #
@@ -190,7 +211,7 @@ module ActiveRecord
190
211
  # given block. This is required for Oracle and is useful for any
191
212
  # database which relies on sequences for primary key generation.
192
213
  #
193
- # If a sequence name is not explicitly set when using Oracle or Firebird,
214
+ # If a sequence name is not explicitly set when using Oracle,
194
215
  # it will default to the commonly used pattern of: #{table_name}_seq
195
216
  #
196
217
  # If a sequence name is not explicitly set when using PostgreSQL, it
@@ -209,50 +230,29 @@ module ActiveRecord
209
230
  connection.schema_cache.table_exists?(table_name)
210
231
  end
211
232
 
212
- # Returns an array of column objects for the table associated with this class.
213
- def columns
214
- @columns ||= connection.schema_cache.columns(table_name).map do |col|
215
- col = col.dup
216
- col.primary = (col.name == primary_key)
217
- col
218
- end
219
- end
220
-
221
- # Returns a hash of column objects for the table associated with this class.
222
- def columns_hash
223
- @columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
233
+ def attributes_builder # :nodoc:
234
+ @attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
224
235
  end
225
236
 
226
237
  def column_types # :nodoc:
227
- @column_types ||= decorate_columns(columns_hash.dup)
228
- end
229
-
230
- def decorate_columns(columns_hash) # :nodoc:
231
- return if columns_hash.empty?
232
-
233
- @serialized_column_names ||= self.columns_hash.keys.find_all do |name|
234
- serialized_attributes.key?(name)
235
- end
236
-
237
- @serialized_column_names.each do |name|
238
- columns_hash[name] = AttributeMethods::Serialization::Type.new(columns_hash[name])
239
- end
240
-
241
- @time_zone_column_names ||= self.columns_hash.find_all do |name, col|
242
- create_time_zone_conversion_attribute?(name, col)
243
- end.map!(&:first)
244
-
245
- @time_zone_column_names.each do |name|
246
- columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(columns_hash[name])
238
+ @column_types ||= columns_hash.transform_values(&:cast_type).tap do |h|
239
+ h.default = Type::Value.new
247
240
  end
241
+ end
248
242
 
249
- columns_hash
243
+ def type_for_attribute(attr_name) # :nodoc:
244
+ column_types[attr_name]
250
245
  end
251
246
 
252
247
  # Returns a hash where the keys are column names and the values are
253
248
  # default values when instantiating the AR object for this table.
254
249
  def column_defaults
255
- @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }]
250
+ _default_attributes.to_hash
251
+ end
252
+
253
+ def _default_attributes # :nodoc:
254
+ @default_attributes ||= attributes_builder.build_from_database(
255
+ raw_default_values)
256
256
  end
257
257
 
258
258
  # Returns an array of column names as strings.
@@ -263,7 +263,7 @@ module ActiveRecord
263
263
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
264
264
  # and columns used for single table inheritance have been removed.
265
265
  def content_columns
266
- @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
266
+ @content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
267
267
  end
268
268
 
269
269
  # Resets all the cached information about columns, which will cause them
@@ -297,26 +297,13 @@ module ActiveRecord
297
297
  undefine_attribute_methods
298
298
  connection.schema_cache.clear_table_cache!(table_name) if table_exists?
299
299
 
300
- @arel_engine = nil
301
- @column_defaults = nil
302
- @column_names = nil
303
- @columns = nil
304
- @columns_hash = nil
305
- @column_types = nil
306
- @content_columns = nil
307
- @dynamic_methods_hash = nil
308
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
309
- @relation = nil
310
- @serialized_column_names = nil
311
- @time_zone_column_names = nil
312
- @cached_time_zone = nil
313
- end
314
-
315
- # This is a hook for use by modules that need to do extra stuff to
316
- # attributes when they are initialized. (e.g. attribute
317
- # serialization)
318
- def initialize_attributes(attributes, options = {}) #:nodoc:
319
- attributes
300
+ @arel_engine = nil
301
+ @column_names = nil
302
+ @column_types = nil
303
+ @content_columns = nil
304
+ @default_attributes = nil
305
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
306
+ @relation = nil
320
307
  end
321
308
 
322
309
  private
@@ -337,12 +324,17 @@ module ActiveRecord
337
324
  contained = contained.singularize if parent.pluralize_table_names
338
325
  contained += '_'
339
326
  end
340
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
327
+
328
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
341
329
  else
342
330
  # STI subclasses always use their superclass' table.
343
331
  base.table_name
344
332
  end
345
333
  end
334
+
335
+ def raw_default_values
336
+ columns_hash.transform_values(&:default)
337
+ end
346
338
  end
347
339
  end
348
340
  end
@@ -305,7 +305,7 @@ module ActiveRecord
305
305
  options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
306
306
 
307
307
  attr_names.each do |association_name|
308
- if reflection = reflect_on_association(association_name)
308
+ if reflection = _reflect_on_association(association_name)
309
309
  reflection.autosave = true
310
310
  add_autosave_association_callbacks(reflection)
311
311
 
@@ -485,10 +485,10 @@ module ActiveRecord
485
485
  end
486
486
 
487
487
  # Takes in a limit and checks if the attributes_collection has too many
488
- # records. The method will take limits in the form of symbols, procs, and
489
- # number-like objects (anything that can be compared with an integer).
488
+ # records. It accepts limit in the form of symbol, proc, or
489
+ # number-like object (anything that can be compared with an integer).
490
490
  #
491
- # Will raise an TooManyRecords error if the attributes_collection is
491
+ # Raises TooManyRecords error if the attributes_collection is
492
492
  # larger than the limit.
493
493
  def check_record_limit!(limit, attributes_collection)
494
494
  if limit
@@ -516,10 +516,10 @@ module ActiveRecord
516
516
 
517
517
  # Determines if a hash contains a truthy _destroy key.
518
518
  def has_destroy_flag?(hash)
519
- ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
519
+ Type::Boolean.new.type_cast_from_user(hash['_destroy'])
520
520
  end
521
521
 
522
- # Determines if a new record should be build by checking for
522
+ # Determines if a new record should be rejected by checking
523
523
  # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
524
524
  # association and evaluates to +true+.
525
525
  def reject_new_record?(association_name, attributes)
@@ -542,7 +542,7 @@ module ActiveRecord
542
542
  end
543
543
 
544
544
  def raise_nested_attributes_record_not_found!(association_name, record_id)
545
- raise RecordNotFound, "Couldn't find #{self.class.reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
545
+ raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
546
546
  end
547
547
  end
548
548
  end