activerecord 4.1.15 → 4.2.0.beta1

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2176
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/association_scope.rb +53 -21
  7. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  8. data/lib/active_record/associations/builder/association.rb +16 -5
  9. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  10. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  11. data/lib/active_record/associations/builder/has_one.rb +2 -2
  12. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  13. data/lib/active_record/associations/collection_association.rb +32 -44
  14. data/lib/active_record/associations/collection_proxy.rb +1 -10
  15. data/lib/active_record/associations/has_many_association.rb +60 -14
  16. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  17. data/lib/active_record/associations/has_one_association.rb +0 -1
  18. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  19. data/lib/active_record/associations/join_dependency.rb +7 -9
  20. data/lib/active_record/associations/preloader/association.rb +9 -5
  21. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/singular_association.rb +16 -1
  24. data/lib/active_record/associations/through_association.rb +6 -22
  25. data/lib/active_record/associations.rb +58 -33
  26. data/lib/active_record/attribute.rb +131 -0
  27. data/lib/active_record/attribute_assignment.rb +19 -11
  28. data/lib/active_record/attribute_decorators.rb +66 -0
  29. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  30. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  31. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  32. data/lib/active_record/attribute_methods/read.rb +14 -57
  33. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  34. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  35. data/lib/active_record/attribute_methods/write.rb +8 -23
  36. data/lib/active_record/attribute_methods.rb +53 -90
  37. data/lib/active_record/attribute_set/builder.rb +32 -0
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attributes.rb +122 -0
  40. data/lib/active_record/autosave_association.rb +11 -21
  41. data/lib/active_record/base.rb +9 -19
  42. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  43. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  45. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  46. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  47. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  48. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  49. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  50. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  51. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  52. data/lib/active_record/connection_adapters/column.rb +13 -244
  53. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  55. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  56. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  57. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  58. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  59. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  60. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  61. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  85. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  86. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  87. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  88. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  89. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  90. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  91. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  93. data/lib/active_record/connection_handling.rb +1 -1
  94. data/lib/active_record/core.rb +119 -22
  95. data/lib/active_record/counter_cache.rb +60 -6
  96. data/lib/active_record/enum.rb +9 -10
  97. data/lib/active_record/errors.rb +27 -26
  98. data/lib/active_record/explain.rb +1 -1
  99. data/lib/active_record/fixtures.rb +52 -45
  100. data/lib/active_record/gem_version.rb +3 -3
  101. data/lib/active_record/inheritance.rb +33 -8
  102. data/lib/active_record/integration.rb +4 -4
  103. data/lib/active_record/locking/optimistic.rb +34 -16
  104. data/lib/active_record/migration/command_recorder.rb +19 -2
  105. data/lib/active_record/migration/join_table.rb +1 -1
  106. data/lib/active_record/migration.rb +22 -32
  107. data/lib/active_record/model_schema.rb +39 -48
  108. data/lib/active_record/nested_attributes.rb +8 -18
  109. data/lib/active_record/persistence.rb +39 -22
  110. data/lib/active_record/query_cache.rb +3 -3
  111. data/lib/active_record/querying.rb +1 -8
  112. data/lib/active_record/railtie.rb +17 -10
  113. data/lib/active_record/railties/databases.rake +47 -42
  114. data/lib/active_record/readonly_attributes.rb +0 -1
  115. data/lib/active_record/reflection.rb +225 -92
  116. data/lib/active_record/relation/batches.rb +0 -2
  117. data/lib/active_record/relation/calculations.rb +28 -32
  118. data/lib/active_record/relation/delegation.rb +1 -1
  119. data/lib/active_record/relation/finder_methods.rb +42 -20
  120. data/lib/active_record/relation/merger.rb +0 -1
  121. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  122. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/query_methods.rb +98 -62
  125. data/lib/active_record/relation/spawn_methods.rb +6 -7
  126. data/lib/active_record/relation.rb +35 -11
  127. data/lib/active_record/result.rb +16 -9
  128. data/lib/active_record/sanitization.rb +8 -1
  129. data/lib/active_record/schema.rb +0 -1
  130. data/lib/active_record/schema_dumper.rb +51 -9
  131. data/lib/active_record/schema_migration.rb +4 -0
  132. data/lib/active_record/scoping/default.rb +5 -4
  133. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  134. data/lib/active_record/statement_cache.rb +79 -5
  135. data/lib/active_record/store.rb +5 -5
  136. data/lib/active_record/tasks/database_tasks.rb +37 -5
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  138. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  139. data/lib/active_record/timestamp.rb +9 -7
  140. data/lib/active_record/transactions.rb +35 -21
  141. data/lib/active_record/type/binary.rb +40 -0
  142. data/lib/active_record/type/boolean.rb +19 -0
  143. data/lib/active_record/type/date.rb +46 -0
  144. data/lib/active_record/type/date_time.rb +43 -0
  145. data/lib/active_record/type/decimal.rb +40 -0
  146. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  147. data/lib/active_record/type/float.rb +19 -0
  148. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  149. data/lib/active_record/type/integer.rb +23 -0
  150. data/lib/active_record/type/mutable.rb +16 -0
  151. data/lib/active_record/type/numeric.rb +36 -0
  152. data/lib/active_record/type/serialized.rb +51 -0
  153. data/lib/active_record/type/string.rb +36 -0
  154. data/lib/active_record/type/text.rb +11 -0
  155. data/lib/active_record/type/time.rb +26 -0
  156. data/lib/active_record/type/time_value.rb +38 -0
  157. data/lib/active_record/type/type_map.rb +48 -0
  158. data/lib/active_record/type/value.rb +101 -0
  159. data/lib/active_record/type.rb +20 -0
  160. data/lib/active_record/validations/uniqueness.rb +9 -23
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record.rb +2 -1
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -195,7 +195,7 @@ module ActiveRecord
195
195
  # == Database support
196
196
  #
197
197
  # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
198
- # SQL Server, Sybase, and Oracle (all supported databases except DB2).
198
+ # SQL Server, and Oracle (all supported databases except DB2).
199
199
  #
200
200
  # == More examples
201
201
  #
@@ -372,13 +372,21 @@ module ActiveRecord
372
372
  end
373
373
 
374
374
  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
375
+ if connection.supports_migrations?
376
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
377
+ if @last_check < mtime
378
+ ActiveRecord::Migration.check_pending!(connection)
379
+ @last_check = mtime
380
+ end
379
381
  end
380
382
  @app.call(env)
381
383
  end
384
+
385
+ private
386
+
387
+ def connection
388
+ ActiveRecord::Base.connection
389
+ end
382
390
  end
383
391
 
384
392
  class << self
@@ -391,14 +399,7 @@ module ActiveRecord
391
399
 
392
400
  def load_schema_if_pending!
393
401
  if ActiveRecord::Migrator.needs_migration?
394
- # Roundrip to Rake to allow plugins to hook into database initialization.
395
- FileUtils.cd Rails.root do
396
- current_config = Base.connection_config
397
- Base.clear_all_connections!
398
- system("bin/rake db:test:prepare")
399
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
400
- Base.establish_connection(current_config)
401
- end
402
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current
402
403
  check_pending!
403
404
  end
404
405
  end
@@ -649,7 +650,9 @@ module ActiveRecord
649
650
  unless @connection.respond_to? :revert
650
651
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
651
652
  arguments[0] = proper_table_name(arguments.first, table_name_options)
652
- arguments[1] = proper_table_name(arguments.second, table_name_options) if method == :rename_table
653
+ if [:rename_table, :add_foreign_key].include?(method)
654
+ arguments[1] = proper_table_name(arguments.second, table_name_options)
655
+ end
653
656
  end
654
657
  end
655
658
  return super unless connection.respond_to?(method)
@@ -811,22 +814,22 @@ module ActiveRecord
811
814
  migrations = migrations(migrations_paths)
812
815
  migrations.select! { |m| yield m } if block_given?
813
816
 
814
- self.new(:up, migrations, target_version).migrate
817
+ new(:up, migrations, target_version).migrate
815
818
  end
816
819
 
817
820
  def down(migrations_paths, target_version = nil, &block)
818
821
  migrations = migrations(migrations_paths)
819
822
  migrations.select! { |m| yield m } if block_given?
820
823
 
821
- self.new(:down, migrations, target_version).migrate
824
+ new(:down, migrations, target_version).migrate
822
825
  end
823
826
 
824
827
  def run(direction, migrations_paths, target_version)
825
- self.new(direction, migrations(migrations_paths), target_version).run
828
+ new(direction, migrations(migrations_paths), target_version).run
826
829
  end
827
830
 
828
831
  def open(migrations_paths)
829
- self.new(:up, migrations(migrations_paths), nil)
832
+ new(:up, migrations(migrations_paths), nil)
830
833
  end
831
834
 
832
835
  def schema_migrations_table_name
@@ -857,19 +860,6 @@ module ActiveRecord
857
860
  migrations(migrations_paths).last || NullMigration.new
858
861
  end
859
862
 
860
- def proper_table_name(name, options = {})
861
- 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"
862
- options = {
863
- table_name_prefix: ActiveRecord::Base.table_name_prefix,
864
- table_name_suffix: ActiveRecord::Base.table_name_suffix
865
- }.merge(options)
866
- if name.respond_to? :table_name
867
- name.table_name
868
- else
869
- "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
870
- end
871
- end
872
-
873
863
  def migrations_paths
874
864
  @migrations_paths ||= ['db/migrate']
875
865
  # just to not break things if someone uses: migration_path = some_string
@@ -901,7 +891,7 @@ module ActiveRecord
901
891
  private
902
892
 
903
893
  def move(direction, migrations_paths, steps)
904
- migrator = self.new(direction, migrations(migrations_paths))
894
+ migrator = new(direction, migrations(migrations_paths))
905
895
  start_index = migrator.migrations.index(migrator.current_migration)
906
896
 
907
897
  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').gsub("\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)
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
+ columns_hash.transform_values(&:default))
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
@@ -298,27 +298,17 @@ module ActiveRecord
298
298
  connection.schema_cache.clear_table_cache!(table_name) if table_exists?
299
299
 
300
300
  @arel_engine = nil
301
- @column_defaults = nil
302
301
  @column_names = nil
303
- @columns = nil
304
- @columns_hash = nil
305
302
  @column_types = nil
306
303
  @content_columns = nil
304
+ @default_attributes = nil
307
305
  @dynamic_methods_hash = nil
308
306
  @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
309
307
  @relation = nil
310
- @serialized_column_names = nil
311
308
  @time_zone_column_names = nil
312
309
  @cached_time_zone = nil
313
310
  end
314
311
 
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
320
- end
321
-
322
312
  private
323
313
 
324
314
  # Guesses the table name, but does not decorate it with prefix and suffix information.
@@ -337,7 +327,8 @@ module ActiveRecord
337
327
  contained = contained.singularize if parent.pluralize_table_names
338
328
  contained += '_'
339
329
  end
340
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
330
+
331
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
341
332
  else
342
333
  # STI subclasses always use their superclass' table.
343
334
  base.table_name
@@ -307,7 +307,7 @@ module ActiveRecord
307
307
  attr_names.each do |association_name|
308
308
  if reflection = _reflect_on_association(association_name)
309
309
  reflection.autosave = true
310
- define_autosave_validation_callbacks(reflection)
310
+ add_autosave_association_callbacks(reflection)
311
311
 
312
312
  nested_attributes_options = self.nested_attributes_options.dup
313
313
  nested_attributes_options[association_name.to_sym] = options
@@ -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,14 +516,14 @@ 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)
526
- will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
526
+ has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
527
527
  end
528
528
 
529
529
  # Determines if a record with the particular +attributes+ should be
@@ -532,8 +532,7 @@ module ActiveRecord
532
532
  #
533
533
  # Returns false if there is a +destroy_flag+ on the attributes.
534
534
  def call_reject_if(association_name, attributes)
535
- return false if will_be_destroyed?(association_name, attributes)
536
-
535
+ return false if has_destroy_flag?(attributes)
537
536
  case callback = self.nested_attributes_options[association_name][:reject_if]
538
537
  when Symbol
539
538
  method(callback).arity == 0 ? send(callback) : send(callback, attributes)
@@ -542,15 +541,6 @@ module ActiveRecord
542
541
  end
543
542
  end
544
543
 
545
- # Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
546
- def will_be_destroyed?(association_name, attributes)
547
- allow_destroy?(association_name) && has_destroy_flag?(attributes)
548
- end
549
-
550
- def allow_destroy?(association_name)
551
- self.nested_attributes_options[association_name][:allow_destroy]
552
- end
553
-
554
544
  def raise_nested_attributes_record_not_found!(association_name, record_id)
555
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}"
556
546
  end
@@ -36,6 +36,23 @@ module ActiveRecord
36
36
  end
37
37
  end
38
38
 
39
+ # Creates an object (or multiple objects) and saves it to the database,
40
+ # if validations pass. Raises a RecordInvalid error if validations fail,
41
+ # unlike Base#create.
42
+ #
43
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes.
44
+ # These describe which attributes to be created on the object, or
45
+ # multiple objects when given an Array of Hashes.
46
+ def create!(attributes = nil, &block)
47
+ if attributes.is_a?(Array)
48
+ attributes.collect { |attr| create!(attr, &block) }
49
+ else
50
+ object = new(attributes, &block)
51
+ object.save!
52
+ object
53
+ end
54
+ end
55
+
39
56
  # Given an attributes hash, +instantiate+ returns a new instance of
40
57
  # the appropriate class. Accepts only keys as strings.
41
58
  #
@@ -48,8 +65,8 @@ module ActiveRecord
48
65
  # how this "single-table" inheritance mapping is implemented.
49
66
  def instantiate(attributes, column_types = {})
50
67
  klass = discriminate_class_for_record(attributes)
51
- column_types = klass.decorate_columns(column_types.dup)
52
- klass.allocate.init_with('attributes' => attributes, 'column_types' => column_types)
68
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
+ klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
53
70
  end
54
71
 
55
72
  private
@@ -180,9 +197,7 @@ module ActiveRecord
180
197
  def becomes(klass)
181
198
  became = klass.new
182
199
  became.instance_variable_set("@attributes", @attributes)
183
- became.instance_variable_set("@attributes_cache", @attributes_cache)
184
- changed_attributes = @changed_attributes if defined?(@changed_attributes)
185
- became.instance_variable_set("@changed_attributes", changed_attributes || {})
200
+ became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
186
201
  became.instance_variable_set("@new_record", new_record?)
187
202
  became.instance_variable_set("@destroyed", destroyed?)
188
203
  became.instance_variable_set("@errors", errors)
@@ -215,6 +230,8 @@ module ActiveRecord
215
230
  #
216
231
  # This method raises an +ActiveRecord::ActiveRecordError+ if the
217
232
  # attribute is marked as readonly.
233
+ #
234
+ # See also +update_column+.
218
235
  def update_attribute(name, value)
219
236
  name = name.to_s
220
237
  verify_readonly_attribute(name)
@@ -270,7 +287,8 @@ module ActiveRecord
270
287
  # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
271
288
  # objects, or when at least one of the attributes is marked as readonly.
272
289
  def update_columns(attributes)
273
- raise ActiveRecordError, "cannot update on a new record object" unless persisted?
290
+ raise ActiveRecordError, "cannot update a new record" if new_record?
291
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
274
292
 
275
293
  attributes.each_key do |key|
276
294
  verify_readonly_attribute(key.to_s)
@@ -395,25 +413,24 @@ module ActiveRecord
395
413
  self.class.unscoped { self.class.find(id) }
396
414
  end
397
415
 
398
- @attributes.update(fresh_object.instance_variable_get('@attributes'))
399
-
400
- @column_types = self.class.column_types
401
- @column_types_override = fresh_object.instance_variable_get('@column_types_override')
402
- @attributes_cache = {}
403
- @new_record = false
416
+ @attributes = fresh_object.instance_variable_get('@attributes')
417
+ @new_record = false
404
418
  self
405
419
  end
406
420
 
407
421
  # Saves the record with the updated_at/on attributes set to the current time.
408
422
  # Please note that no validation is performed and only the +after_touch+,
409
423
  # +after_commit+ and +after_rollback+ callbacks are executed.
410
- # If an attribute name is passed, that attribute is updated along with
411
- # updated_at/on attributes.
412
424
  #
413
- # product.touch # updates updated_at/on
414
- # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
425
+ # If attribute names are passed, they are updated along with updated_at/on
426
+ # attributes.
427
+ #
428
+ # product.touch # updates updated_at/on
429
+ # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
430
+ # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
415
431
  #
416
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
432
+ # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
433
+ # associated object.
417
434
  #
418
435
  # class Brake < ActiveRecord::Base
419
436
  # belongs_to :car, touch: true
@@ -432,11 +449,11 @@ module ActiveRecord
432
449
  # ball = Ball.new
433
450
  # ball.touch(:updated_at) # => raises ActiveRecordError
434
451
  #
435
- def touch(name = nil)
452
+ def touch(*names)
436
453
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
437
454
 
438
455
  attributes = timestamp_attributes_for_update_in_model
439
- attributes << name if name
456
+ attributes.concat(names)
440
457
 
441
458
  unless attributes.empty?
442
459
  current_time = current_time_from_proper_timezone
@@ -449,7 +466,7 @@ module ActiveRecord
449
466
 
450
467
  changes[self.class.locking_column] = increment_lock if locking_enabled?
451
468
 
452
- changed_attributes.except!(*changes.keys)
469
+ clear_attribute_changes(changes.keys)
453
470
  primary_key = self.class.primary_key
454
471
  self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
455
472
  else
@@ -487,7 +504,7 @@ module ActiveRecord
487
504
 
488
505
  # Updates the associated record with values matching those of the instance attributes.
489
506
  # Returns the number of affected rows.
490
- def _update_record(attribute_names = @attributes.keys)
507
+ def _update_record(attribute_names = self.attribute_names)
491
508
  attributes_values = arel_attributes_with_values_for_update(attribute_names)
492
509
  if attributes_values.empty?
493
510
  0
@@ -498,7 +515,7 @@ module ActiveRecord
498
515
 
499
516
  # Creates a record with values matching those of the instance attributes
500
517
  # and returns its id.
501
- def _create_record(attribute_names = @attributes.keys)
518
+ def _create_record(attribute_names = self.attribute_names)
502
519
  attributes_values = arel_attributes_with_values_for_create(attribute_names)
503
520
 
504
521
  new_id = self.class.unscoped.insert attributes_values
@@ -1,4 +1,3 @@
1
-
2
1
  module ActiveRecord
3
2
  # = Active Record Query Cache
4
3
  class QueryCache
@@ -29,9 +28,10 @@ module ActiveRecord
29
28
  end
30
29
 
31
30
  def call(env)
32
- enabled = ActiveRecord::Base.connection.query_cache_enabled
31
+ connection = ActiveRecord::Base.connection
32
+ enabled = connection.query_cache_enabled
33
33
  connection_id = ActiveRecord::Base.connection_id
34
- ActiveRecord::Base.connection.enable_query_cache!
34
+ connection.enable_query_cache!
35
35
 
36
36
  response = @app.call(env)
37
37
  response[2] = Rack::BodyProxy.new(response[2]) do
@@ -37,14 +37,7 @@ module ActiveRecord
37
37
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
38
38
  def find_by_sql(sql, binds = [])
39
39
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
40
- column_types = {}
41
-
42
- if result_set.respond_to? :column_types
43
- column_types = result_set.column_types
44
- else
45
- ActiveSupport::Deprecation.warn "the object returned from `select_all` must respond to `column_types`"
46
- end
47
-
40
+ column_types = result_set.column_types.except(*columns_hash.keys)
48
41
  result_set.map { |record| instantiate(record, column_types) }
49
42
  end
50
43
 
@@ -36,6 +36,8 @@ module ActiveRecord
36
36
  config.eager_load_namespaces << ActiveRecord
37
37
 
38
38
  rake_tasks do
39
+ require "active_record/base"
40
+
39
41
  namespace :db do
40
42
  task :load_config do
41
43
  ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
@@ -114,17 +116,22 @@ module ActiveRecord
114
116
  # and then establishes the connection.
115
117
  initializer "active_record.initialize_database" do |app|
116
118
  ActiveSupport.on_load(:active_record) do
119
+ self.configurations = Rails.application.config.database_configuration
117
120
 
118
- class ActiveRecord::NoDatabaseError
119
- remove_possible_method :extend_message
120
- def extend_message(message)
121
- message << "Run `$ bin/rake db:create db:migrate` to create your database"
122
- message
123
- end
124
- end
121
+ begin
122
+ establish_connection
123
+ rescue ActiveRecord::NoDatabaseError
124
+ warn <<-end_warning
125
+ Oops - You have a database configured, but it doesn't exist yet!
125
126
 
126
- self.configurations = Rails.application.config.database_configuration
127
- establish_connection
127
+ Here's how to get started:
128
+
129
+ 1. Configure your database in config/database.yml.
130
+ 2. Run `bin/rake db:create` to create the database.
131
+ 3. Run `bin/rake db:setup` to load your database schema.
132
+ end_warning
133
+ raise
134
+ end
128
135
  end
129
136
  end
130
137
 
@@ -142,8 +149,8 @@ module ActiveRecord
142
149
  ActiveSupport.on_load(:active_record) do
143
150
  ActionDispatch::Reloader.send(hook) do
144
151
  if ActiveRecord::Base.connected?
145
- ActiveRecord::Base.clear_cache!
146
152
  ActiveRecord::Base.clear_reloadable_connections!
153
+ ActiveRecord::Base.clear_cache!
147
154
  end
148
155
  end
149
156
  end