activerecord 4.1.8 → 4.2.11.3

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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1165 -1591
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +84 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +87 -30
  18. data/lib/active_record/associations/collection_proxy.rb +33 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -12
  26. data/lib/active_record/associations/preloader/association.rb +14 -10
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +37 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +16 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +20 -12
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +57 -95
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +30 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -40
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +10 -12
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +62 -74
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +79 -47
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +18 -8
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +48 -27
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +19 -14
  126. data/lib/active_record/railties/databases.rake +55 -56
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +281 -117
  129. data/lib/active_record/relation/batches.rb +0 -1
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/delegation.rb +1 -1
  132. data/lib/active_record/relation/finder_methods.rb +71 -48
  133. data/lib/active_record/relation/merger.rb +39 -29
  134. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  135. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  136. data/lib/active_record/relation/predicate_builder.rb +42 -12
  137. data/lib/active_record/relation/query_methods.rb +130 -73
  138. data/lib/active_record/relation/spawn_methods.rb +10 -3
  139. data/lib/active_record/relation.rb +57 -25
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -8
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +54 -28
  155. data/lib/active_record/type/big_integer.rb +13 -0
  156. data/lib/active_record/type/binary.rb +50 -0
  157. data/lib/active_record/type/boolean.rb +31 -0
  158. data/lib/active_record/type/date.rb +50 -0
  159. data/lib/active_record/type/date_time.rb +54 -0
  160. data/lib/active_record/type/decimal.rb +64 -0
  161. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  162. data/lib/active_record/type/decorator.rb +14 -0
  163. data/lib/active_record/type/float.rb +19 -0
  164. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  165. data/lib/active_record/type/integer.rb +59 -0
  166. data/lib/active_record/type/mutable.rb +16 -0
  167. data/lib/active_record/type/numeric.rb +36 -0
  168. data/lib/active_record/type/serialized.rb +62 -0
  169. data/lib/active_record/type/string.rb +40 -0
  170. data/lib/active_record/type/text.rb +11 -0
  171. data/lib/active_record/type/time.rb +26 -0
  172. data/lib/active_record/type/time_value.rb +38 -0
  173. data/lib/active_record/type/type_map.rb +64 -0
  174. data/lib/active_record/type/unsigned_integer.rb +15 -0
  175. data/lib/active_record/type/value.rb +110 -0
  176. data/lib/active_record/type.rb +23 -0
  177. data/lib/active_record/validations/associated.rb +5 -3
  178. data/lib/active_record/validations/presence.rb +5 -3
  179. data/lib/active_record/validations/uniqueness.rb +24 -20
  180. data/lib/active_record/validations.rb +25 -19
  181. data/lib/active_record.rb +5 -0
  182. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  183. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  184. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  185. metadata +66 -11
  186. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
 
40
40
  class PendingMigrationError < MigrationError#:nodoc:
41
41
  def initialize
42
- if defined?(Rails)
42
+ if defined?(Rails.env)
43
43
  super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
44
44
  else
45
45
  super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
@@ -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
  #
@@ -311,9 +307,8 @@ module ActiveRecord
311
307
  #
312
308
  # == Reversible Migrations
313
309
  #
314
- # Starting with Rails 3.1, you will be able to define reversible migrations.
315
310
  # Reversible migrations are migrations that know how to go +down+ for you.
316
- # You simply supply the +up+ logic, and the Migration system will figure out
311
+ # You simply supply the +up+ logic, and the Migration system figures out
317
312
  # how to execute the down commands for you.
318
313
  #
319
314
  # To define a reversible migration, define the +change+ method in your
@@ -372,13 +367,21 @@ module ActiveRecord
372
367
  end
373
368
 
374
369
  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
370
+ if connection.supports_migrations?
371
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
372
+ if @last_check < mtime
373
+ ActiveRecord::Migration.check_pending!(connection)
374
+ @last_check = mtime
375
+ end
379
376
  end
380
377
  @app.call(env)
381
378
  end
379
+
380
+ private
381
+
382
+ def connection
383
+ ActiveRecord::Base.connection
384
+ end
382
385
  end
383
386
 
384
387
  class << self
@@ -390,8 +393,15 @@ module ActiveRecord
390
393
  end
391
394
 
392
395
  def load_schema_if_pending!
393
- if ActiveRecord::Migrator.needs_migration?
394
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current
396
+ if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
397
+ # Roundrip to Rake to allow plugins to hook into database initialization.
398
+ FileUtils.cd Rails.root do
399
+ current_config = Base.connection_config
400
+ Base.clear_all_connections!
401
+ system("bin/rake db:test:prepare")
402
+ # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
403
+ Base.establish_connection(current_config)
404
+ end
395
405
  check_pending!
396
406
  end
397
407
  end
@@ -410,7 +420,10 @@ module ActiveRecord
410
420
  new.migrate direction
411
421
  end
412
422
 
413
- # Disable DDL transactions for this migration.
423
+ # Disable the transaction wrapping this migration.
424
+ # You can still create your own transactions even after calling #disable_ddl_transaction!
425
+ #
426
+ # For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
414
427
  def disable_ddl_transaction!
415
428
  @disable_ddl_transaction = true
416
429
  end
@@ -642,7 +655,10 @@ module ActiveRecord
642
655
  unless @connection.respond_to? :revert
643
656
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
644
657
  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
658
+ if [:rename_table, :add_foreign_key].include?(method) ||
659
+ (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
660
+ arguments[1] = proper_table_name(arguments.second, table_name_options)
661
+ end
646
662
  end
647
663
  end
648
664
  return super unless connection.respond_to?(method)
@@ -804,22 +820,22 @@ module ActiveRecord
804
820
  migrations = migrations(migrations_paths)
805
821
  migrations.select! { |m| yield m } if block_given?
806
822
 
807
- self.new(:up, migrations, target_version).migrate
823
+ new(:up, migrations, target_version).migrate
808
824
  end
809
825
 
810
826
  def down(migrations_paths, target_version = nil, &block)
811
827
  migrations = migrations(migrations_paths)
812
828
  migrations.select! { |m| yield m } if block_given?
813
829
 
814
- self.new(:down, migrations, target_version).migrate
830
+ new(:down, migrations, target_version).migrate
815
831
  end
816
832
 
817
833
  def run(direction, migrations_paths, target_version)
818
- self.new(direction, migrations(migrations_paths), target_version).run
834
+ new(direction, migrations(migrations_paths), target_version).run
819
835
  end
820
836
 
821
837
  def open(migrations_paths)
822
- self.new(:up, migrations(migrations_paths), nil)
838
+ new(:up, migrations(migrations_paths), nil)
823
839
  end
824
840
 
825
841
  def schema_migrations_table_name
@@ -842,6 +858,10 @@ module ActiveRecord
842
858
  (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
843
859
  end
844
860
 
861
+ def any_migrations?
862
+ migrations(migrations_paths).any?
863
+ end
864
+
845
865
  def last_version
846
866
  last_migration.version
847
867
  end
@@ -850,19 +870,6 @@ module ActiveRecord
850
870
  migrations(migrations_paths).last || NullMigration.new
851
871
  end
852
872
 
853
- def proper_table_name(name, options = {})
854
- 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"
855
- options = {
856
- table_name_prefix: ActiveRecord::Base.table_name_prefix,
857
- table_name_suffix: ActiveRecord::Base.table_name_suffix
858
- }.merge(options)
859
- if name.respond_to? :table_name
860
- name.table_name
861
- else
862
- "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
863
- end
864
- end
865
-
866
873
  def migrations_paths
867
874
  @migrations_paths ||= ['db/migrate']
868
875
  # just to not break things if someone uses: migration_path = some_string
@@ -873,14 +880,15 @@ module ActiveRecord
873
880
  migrations_paths.first
874
881
  end
875
882
 
883
+ def parse_migration_filename(filename) # :nodoc:
884
+ File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
885
+ end
886
+
876
887
  def migrations(paths)
877
888
  paths = Array(paths)
878
889
 
879
- files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
880
-
881
- migrations = files.map do |file|
882
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
883
-
890
+ migrations = migration_files(paths).map do |file|
891
+ version, name, scope = parse_migration_filename(file)
884
892
  raise IllegalMigrationNameError.new(file) unless version
885
893
  version = version.to_i
886
894
  name = name.camelize
@@ -891,10 +899,34 @@ module ActiveRecord
891
899
  migrations.sort_by(&:version)
892
900
  end
893
901
 
902
+ def migrations_status(paths)
903
+ paths = Array(paths)
904
+
905
+ db_list = ActiveRecord::SchemaMigration.normalized_versions
906
+
907
+ file_list = migration_files(paths).map do |file|
908
+ version, name, scope = parse_migration_filename(file)
909
+ raise IllegalMigrationNameError.new(file) unless version
910
+ version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
911
+ status = db_list.delete(version) ? "up" : "down"
912
+ [status, version, (name + scope).humanize]
913
+ end.compact
914
+
915
+ db_list.map! do |version|
916
+ ["up", version, "********** NO FILE **********"]
917
+ end
918
+
919
+ (db_list + file_list).sort_by { |_, version, _| version }
920
+ end
921
+
922
+ def migration_files(paths)
923
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
924
+ end
925
+
894
926
  private
895
927
 
896
928
  def move(direction, migrations_paths, steps)
897
- migrator = self.new(direction, migrations(migrations_paths))
929
+ migrator = new(direction, migrations(migrations_paths))
898
930
  start_index = migrator.migrations.index(migrator.current_migration)
899
931
 
900
932
  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.dup.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
@@ -295,28 +295,17 @@ module ActiveRecord
295
295
  def reset_column_information
296
296
  connection.clear_cache!
297
297
  undefine_attribute_methods
298
- connection.schema_cache.clear_table_cache!(table_name) if table_exists?
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
298
+ connection.schema_cache.clear_table_cache!(table_name)
299
+
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
314
307
 
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
308
+ initialize_find_by_cache
320
309
  end
321
310
 
322
311
  private
@@ -337,12 +326,17 @@ module ActiveRecord
337
326
  contained = contained.singularize if parent.pluralize_table_names
338
327
  contained += '_'
339
328
  end
340
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
329
+
330
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
341
331
  else
342
332
  # STI subclasses always use their superclass' table.
343
333
  base.table_name
344
334
  end
345
335
  end
336
+
337
+ def raw_default_values
338
+ columns_hash.transform_values(&:default)
339
+ end
346
340
  end
347
341
  end
348
342
  end
@@ -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
- add_autosave_association_callbacks(reflection)
310
+ define_autosave_validation_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
- has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
526
+ will_be_destroyed?(association_name, 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,7 +532,8 @@ 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 has_destroy_flag?(attributes)
535
+ return false if will_be_destroyed?(association_name, attributes)
536
+
536
537
  case callback = self.nested_attributes_options[association_name][:reject_if]
537
538
  when Symbol
538
539
  method(callback).arity == 0 ? send(callback) : send(callback, attributes)
@@ -541,6 +542,15 @@ module ActiveRecord
541
542
  end
542
543
  end
543
544
 
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
+
544
554
  def raise_nested_attributes_record_not_found!(association_name, record_id)
545
555
  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
556
  end
@@ -45,7 +45,7 @@ module ActiveRecord
45
45
  NoTouching.applied_to?(self.class)
46
46
  end
47
47
 
48
- def touch(*)
48
+ def touch(*) # :nodoc:
49
49
  super unless no_touching?
50
50
  end
51
51
  end