diff --git a/Gemfile b/Gemfile index 2a3e35d..f793f16 100644 --- a/Gemfile +++ b/Gemfile @@ -18,12 +18,7 @@ end case ENV["DB"] when "sqlite" - if ENV["RAILS_VERSION"] && - Gem::Version.new(ENV["RAILS_VERSION"]) >= Gem::Version.new("7.2") - gem "sqlite3", "~> 2.9.0" - else - gem "sqlite3", "~> 1.7.3" - end + gem "sqlite3", "~> 2.9.0" when "postgresql" gem "pg", "~> 1.6.3" else diff --git a/lib/positioning.rb b/lib/positioning.rb index 638de7d..8c52a50 100644 --- a/lib/positioning.rb +++ b/lib/positioning.rb @@ -35,7 +35,7 @@ def positioned(on: [], column: :position) reflection = reflections[scope_component] if reflection&.belongs_to? - positioning_columns[column][:scope_columns] << reflection.foreign_key + positioning_columns[column][:scope_columns].concat Array(reflection.foreign_key) positioning_columns[column][:scope_columns] << reflection.foreign_type if reflection.polymorphic? positioning_columns[column][:scope_associations] << reflection.name else diff --git a/lib/positioning/mechanisms.rb b/lib/positioning/mechanisms.rb index d6bfa69..5813159 100644 --- a/lib/positioning/mechanisms.rb +++ b/lib/positioning/mechanisms.rb @@ -222,7 +222,7 @@ def positioning_scope_changed? def destroyed_via_positioning_scope? @positioned.destroyed_by_association && scope_columns.any? do |scope_column| - @positioned.destroyed_by_association.foreign_key == scope_column + Array(@positioned.destroyed_by_association.foreign_key).include?(scope_column) end end end diff --git a/test/models/composite_foreign_key_item.rb b/test/models/composite_foreign_key_item.rb new file mode 100644 index 0000000..dfb745f --- /dev/null +++ b/test/models/composite_foreign_key_item.rb @@ -0,0 +1,5 @@ +class CompositeForeignKeyItem < ActiveRecord::Base + belongs_to :list, class_name: "CompositePrimaryKeyItem", foreign_key: [:cpki_item_id, :cpki_account_id] + + positioned on: :list +end diff --git a/test/models/composite_primary_key_item.rb b/test/models/composite_primary_key_item.rb index c68df97..0a00292 100644 --- a/test/models/composite_primary_key_item.rb +++ b/test/models/composite_primary_key_item.rb @@ -3,5 +3,7 @@ class CompositePrimaryKeyItem < ActiveRecord::Base belongs_to :list + has_many :composite_foreign_key_items, -> { order(:position) }, foreign_key: [:cpki_item_id, :cpki_account_id], dependent: :destroy + positioned on: :list end diff --git a/test/support/active_record.rb b/test/support/active_record.rb index ca4a300..f1e9522 100644 --- a/test/support/active_record.rb +++ b/test/support/active_record.rb @@ -55,6 +55,15 @@ add_index :composite_primary_key_items, [:list_id, :position], unique: true + create_table :composite_foreign_key_items, force: true do |t| + t.string :name + t.integer :position, null: false + t.integer :cpki_item_id, null: false + t.integer :cpki_account_id, null: false + end + + add_index :composite_foreign_key_items, [:cpki_item_id, :cpki_account_id, :position], unique: true, name: "index_cfki_on_scope_and_position" + create_table :categories, force: true do |t| t.string :name t.integer :position, null: false diff --git a/test/test_helper.rb b/test/test_helper.rb index a2ec3a9..e1cfa10 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,6 +11,7 @@ require_relative "models/new_item" require_relative "models/default_scope_item" require_relative "models/composite_primary_key_item" +require_relative "models/composite_foreign_key_item" require_relative "models/product" require_relative "models/category" require_relative "models/categorised_item" diff --git a/test/test_positioning.rb b/test/test_positioning.rb index d7c1797..6cf39ea 100644 --- a/test/test_positioning.rb +++ b/test/test_positioning.rb @@ -566,6 +566,23 @@ def test_destroyed_via_positioning_scope? list.destroy assert mechanisms.send(:destroyed_via_positioning_scope?) end + + def test_destroyed_via_positioning_scope_with_composite_foreign_key + list = List.create(name: "List") + parent = CompositePrimaryKeyItem.create(item_id: 1, account_id: 1, list: list, name: "Parent") + child1 = parent.composite_foreign_key_items.create(name: "Child 1") + child2 = parent.composite_foreign_key_items.create(name: "Child 2") + + mechanisms = Positioning::Mechanisms.new(child1, :position) + refute mechanisms.send(:destroyed_via_positioning_scope?) + + mechanisms = Positioning::Mechanisms.new(child2, :position) + child2.destroy + refute mechanisms.send(:destroyed_via_positioning_scope?) + + parent.destroy + assert mechanisms.send(:destroyed_via_positioning_scope?) + end end class TestPositioningScopes < Minitest::Test @@ -606,6 +623,13 @@ def test_that_position_columns_will_cope_with_polymorphic_belong_to assert_equal({position: {scope_columns: ["includable_id", "includable_type"], scope_associations: [:includable]}}, Entity.positioning_columns) end + def test_that_position_columns_will_cope_with_composite_foreign_key + assert_equal( + {position: {scope_columns: ["cpki_item_id", "cpki_account_id"], scope_associations: [:list]}}, + CompositeForeignKeyItem.positioning_columns + ) + end + def test_that_position_columns_must_have_unique_keys assert_raises(Positioning::Error) do Item.send :positioned, on: :list @@ -1135,8 +1159,6 @@ def test_destroying_multiple_items class TestCompositePrimaryKeyPositioning < TestPositioning def configure - skip if ActiveRecord.version < Gem::Version.new("7.1.0") - @association = :composite_primary_key_items @id = Enumerator.new do |yielder| number = 1 @@ -1149,6 +1171,38 @@ def configure end end +class TestCompositeForeignKeyPositioning < TestPositioning + def configure + @association = :composite_foreign_key_items + @id = Enumerator.new do |yielder| + loop do + yielder.yield(nil) + end + end + end + + def setup + configure + + list = List.create name: "List" + @first_list = CompositePrimaryKeyItem.create(item_id: 1, account_id: 1, list: list, name: "First List") + @second_list = CompositePrimaryKeyItem.create(item_id: 2, account_id: 2, list: list, name: "Second List") + @first_item = @first_list.send(@association).create id: @id.next, name: "First Item" + @second_item = @first_list.send(@association).create id: @id.next, name: "Second Item" + @third_item = @first_list.send(@association).create id: @id.next, name: "Third Item" + @fourth_item = @second_list.send(@association).create id: @id.next, name: "Fourth Item" + @fifth_item = @second_list.send(@association).create id: @id.next, name: "Fifth Item" + @sixth_item = @second_list.send(@association).create id: @id.next, name: "Sixth Item" + + @models = [ + @first_list, @second_list, @first_item, @second_item, + @third_item, @fourth_item, @fifth_item, @sixth_item + ] + + reload_models + end +end + class TestNoScopePositioning < Minitest::Test include Minitest::Hooks