diff options
Diffstat (limited to 'activerecord')
16 files changed, 128 insertions, 71 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index a61c0336db..ef26f4a20c 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1400,7 +1400,7 @@ module ActiveRecord # has_many :tags, as: :taggable # has_many :reports, -> { readonly } # has_many :subscribers, through: :subscriptions, source: :user - def has_many(name, scope = nil, options = {}, &extension) + def has_many(name, scope = nil, **options, &extension) reflection = Builder::HasMany.build(self, name, scope, options, &extension) Reflection.add_reflection self, name, reflection end @@ -1534,7 +1534,7 @@ module ActiveRecord # has_one :club, through: :membership # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable # has_one :credit_card, required: true - def has_one(name, scope = nil, options = {}) + def has_one(name, scope = nil, **options) reflection = Builder::HasOne.build(self, name, scope, options) Reflection.add_reflection self, name, reflection end @@ -1678,7 +1678,7 @@ module ActiveRecord # belongs_to :company, touch: :employees_last_updated_at # belongs_to :user, optional: true # belongs_to :account, default: -> { company.account } - def belongs_to(name, scope = nil, options = {}) + def belongs_to(name, scope = nil, **options) reflection = Builder::BelongsTo.build(self, name, scope, options) Reflection.add_reflection self, name, reflection end diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 496b16b58f..ca3032d967 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -38,11 +38,6 @@ module ActiveRecord::Associations::Builder # :nodoc: def self.create_reflection(model, name, scope, options, extension = nil) raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol) - if scope.is_a?(Hash) - options = scope - scope = nil - end - validate_options(options) scope = build_scope(scope, extension) diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 9bb6a613e1..fe696e0d6e 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -17,26 +17,20 @@ module ActiveRecord end def run(preloader) - preload(preloader) - end - - def preload(preloader) - raise NotImplementedError - end - - # The name of the key on the associated records - def association_key_name - raise NotImplementedError - end - - # The name of the key on the model which declares the association - def owner_key_name - raise NotImplementedError + associated_records_by_owner(preloader).each do |owner, records| + associate_records_to_owner(owner, records) + end end private - def options - reflection.options + # The name of the key on the associated records + def association_key_name + reflection.join_primary_key(klass) + end + + # The name of the key on the model which declares the association + def owner_key_name + reflection.join_foreign_key end def associated_records_by_owner(preloader) @@ -51,6 +45,10 @@ module ActiveRecord end end + def associate_records_to_owner(owner, records) + raise NotImplementedError + end + def owner_keys unless defined?(@owner_keys) @owner_keys = owners.map do |owner| diff --git a/activerecord/lib/active_record/associations/preloader/belongs_to.rb b/activerecord/lib/active_record/associations/preloader/belongs_to.rb index ae9695f26a..a8e3340b23 100644 --- a/activerecord/lib/active_record/associations/preloader/belongs_to.rb +++ b/activerecord/lib/active_record/associations/preloader/belongs_to.rb @@ -4,13 +4,6 @@ module ActiveRecord module Associations class Preloader class BelongsTo < SingularAssociation #:nodoc: - def association_key_name - options[:primary_key] || klass && klass.primary_key - end - - def owner_key_name - reflection.foreign_key - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb index fb920a642c..fc2029f54a 100644 --- a/activerecord/lib/active_record/associations/preloader/collection_association.rb +++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb @@ -5,13 +5,10 @@ module ActiveRecord class Preloader class CollectionAssociation < Association #:nodoc: private - - def preload(preloader) - associated_records_by_owner(preloader).each do |owner, records| - association = owner.association(reflection.name) - association.loaded! - association.target.concat(records) - end + def associate_records_to_owner(owner, records) + association = owner.association(reflection.name) + association.loaded! + association.target.concat(records) end end end diff --git a/activerecord/lib/active_record/associations/preloader/has_many.rb b/activerecord/lib/active_record/associations/preloader/has_many.rb index 29a1ce099d..72f55bc43f 100644 --- a/activerecord/lib/active_record/associations/preloader/has_many.rb +++ b/activerecord/lib/active_record/associations/preloader/has_many.rb @@ -4,13 +4,6 @@ module ActiveRecord module Associations class Preloader class HasMany < CollectionAssociation #:nodoc: - def association_key_name - reflection.foreign_key - end - - def owner_key_name - reflection.active_record_primary_key - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/has_one.rb b/activerecord/lib/active_record/associations/preloader/has_one.rb index d87abf630f..e339b65fb5 100644 --- a/activerecord/lib/active_record/associations/preloader/has_one.rb +++ b/activerecord/lib/active_record/associations/preloader/has_one.rb @@ -4,13 +4,6 @@ module ActiveRecord module Associations class Preloader class HasOne < SingularAssociation #:nodoc: - def association_key_name - reflection.foreign_key - end - - def owner_key_name - reflection.active_record_primary_key - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb index 266b5f6b1c..30a92411e3 100644 --- a/activerecord/lib/active_record/associations/preloader/singular_association.rb +++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb @@ -5,14 +5,9 @@ module ActiveRecord class Preloader class SingularAssociation < Association #:nodoc: private - - def preload(preloader) - associated_records_by_owner(preloader).each do |owner, associated_records| - record = associated_records.first - - association = owner.association(reflection.name) - association.target = record - end + def associate_records_to_owner(owner, records) + association = owner.association(reflection.name) + association.target = records.first end end end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 53e9c14823..fa32cc5553 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -80,6 +80,7 @@ module ActiveRecord def through_scope scope = through_reflection.klass.unscoped + options = reflection.options if options[:source_type] scope.where! reflection.foreign_type => options[:source_type] diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index f57c7a5d4d..c9607df28c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -522,6 +522,8 @@ module ActiveRecord # Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns. # * <tt>:scale</tt> - # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns. + # * <tt>:comment</tt> - + # Specifies the comment for the column. This option is ignored by some backends. # # Note: The precision is the total number of significant digits, # and the scale is the number of digits that can be stored following diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb index 1b67cee24b..ff95fa4a0e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -10,8 +10,15 @@ module ActiveRecord def serial? return unless default_function - %r{\Anextval\('"?#{table_name}_#{name}_seq"?'::regclass\)\z} === default_function + if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function + sequence_name_from_parts(table_name, name, suffix) == sequence_name + end end + + private + def sequence_name_from_parts(table_name, column_name, suffix) + "#{table_name}_#{column_name}_#{suffix}" + end end end end diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb index 784292f3f9..87c1c58aff 100644 --- a/activerecord/lib/active_record/migration/compatibility.rb +++ b/activerecord/lib/active_record/migration/compatibility.rb @@ -71,6 +71,21 @@ module ActiveRecord end end + def create_join_table(table_1, table_2, column_options: {}, **options) + column_options.reverse_merge!(type: :integer) + + if block_given? + super(table_1, table_2, column_options: column_options, **options) do |t| + class << t + prepend TableDefinition + end + yield t + end + else + super + end + end + def add_reference(table_name, ref_name, **options) super(table_name, ref_name, type: :integer, **options) end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 889e24dd1a..82ab2415e1 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -292,13 +292,17 @@ module ActiveRecord end def get_join_keys(association_klass) - JoinKeys.new(join_pk(association_klass), join_foreign_key) + JoinKeys.new(join_primary_key(association_klass), join_foreign_key) end def build_scope(table, predicate_builder = predicate_builder(table)) Relation.create(klass, table, predicate_builder) end + def join_primary_key(_) + foreign_key + end + def join_foreign_key active_record_primary_key end @@ -313,10 +317,6 @@ module ActiveRecord PredicateBuilder.new(TableMetadata.new(klass, table)) end - def join_pk(_) - foreign_key - end - def primary_key(klass) klass.primary_key || raise(UnknownPrimaryKey.new(klass)) end @@ -736,6 +736,10 @@ module ActiveRecord end end + def join_primary_key(klass) + polymorphic? ? association_primary_key(klass) : association_primary_key + end + def join_foreign_key foreign_key end @@ -745,10 +749,6 @@ module ActiveRecord def calculate_constructable(macro, options) !polymorphic? end - - def join_pk(klass) - polymorphic? ? association_primary_key(klass) : association_primary_key - end end class HasAndBelongsToManyReflection < AssociationReflection # :nodoc: diff --git a/activerecord/test/cases/adapters/postgresql/serial_test.rb b/activerecord/test/cases/adapters/postgresql/serial_test.rb index 3c020a88d0..df7875dbf2 100644 --- a/activerecord/test/cases/adapters/postgresql/serial_test.rb +++ b/activerecord/test/cases/adapters/postgresql/serial_test.rb @@ -86,3 +86,39 @@ class PostgresqlBigSerialTest < ActiveRecord::PostgreSQLTestCase assert_match %r{t\.bigint\s+"serials_id",\s+default: -> \{ "nextval\('postgresql_big_serials_id_seq'::regclass\)" \}$}, output end end + +module SequenceNameDetectionTestCases + class CollidedSequenceNameTest < ActiveRecord::PostgreSQLTestCase + include SchemaDumpingHelper + + def setup + @connection = ActiveRecord::Base.connection + @connection.create_table :foo_bar, force: true do |t| + t.serial :baz_id + end + @connection.create_table :foo, force: true do |t| + t.serial :bar_id + t.bigserial :bar_baz_id + end + end + + def teardown + @connection.drop_table :foo_bar, if_exists: true + @connection.drop_table :foo, if_exists: true + end + + def test_serial_columns + columns = @connection.columns(:foo) + columns.each do |column| + assert_equal :integer, column.type + assert column.serial? + end + end + + def test_schema_dump_with_collided_sequence_name + output = dump_table_schema "foo" + assert_match %r{t\.serial\s+"bar_id",\s+null: false$}, output + assert_match %r{t\.bigserial\s+"bar_baz_id",\s+null: false$}, output + end + end +end diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb index 29a25b4461..2caf2a63d4 100644 --- a/activerecord/test/cases/attributes_test.rb +++ b/activerecord/test/cases/attributes_test.rb @@ -108,12 +108,14 @@ module ActiveRecord assert_equal 6, klass.attribute_types.length assert_equal 6, klass.column_defaults.length + assert_equal 6, klass.attribute_names.length assert_not klass.attribute_types.include?("wibble") klass.attribute :wibble, Type::Value.new assert_equal 7, klass.attribute_types.length assert_equal 7, klass.column_defaults.length + assert_equal 7, klass.attribute_names.length assert_includes klass.attribute_types, "wibble" end diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb index cb3b02c02a..e1311c0f21 100644 --- a/activerecord/test/cases/migration/compatibility_test.rb +++ b/activerecord/test/cases/migration/compatibility_test.rb @@ -199,6 +199,36 @@ class LegacyPrimaryKeyTest < ActiveRecord::TestCase assert_match %r{create_table "legacy_primary_keys", id: :integer, default: nil}, schema end + def test_legacy_join_table_foreign_keys_should_be_integer + @migration = Class.new(ActiveRecord::Migration[5.0]) { + def change + create_join_table :apples, :bananas do |t| + end + end + }.new + + @migration.migrate(:up) + + schema = dump_table_schema "apples_bananas" + assert_match %r{integer "apple_id", null: false}, schema + assert_match %r{integer "banana_id", null: false}, schema + end + + def test_legacy_join_table_column_options_should_be_overwritten + @migration = Class.new(ActiveRecord::Migration[5.0]) { + def change + create_join_table :apples, :bananas, column_options: { type: :bigint } do |t| + end + end + }.new + + @migration.migrate(:up) + + schema = dump_table_schema "apples_bananas" + assert_match %r{bigint "apple_id", null: false}, schema + assert_match %r{bigint "banana_id", null: false}, schema + end + if current_adapter?(:Mysql2Adapter) def test_legacy_bigint_primary_key_should_be_auto_incremented @migration = Class.new(ActiveRecord::Migration[5.0]) { |