Ruby on Rails has_many: уничтожая больше, чем следует

Я создаю приложение, в котором есть три основные модели и отношения между ними, по которым мне нужно отслеживать некоторые свойства:

schema.rb

  create_table "entities", force: true do |t|
    t.string   "name"
    t.string   "label"
    t.string   "img"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "entities", ["name"], name: "index_entities_on_name", unique: true, using: :btree

  create_table "entity_group_relationships", force: true do |t|
    t.integer  "entity_id"
    t.integer  "group_id"
    t.integer  "order"
    t.string   "label"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "entity_group_relationships", ["entity_id", "group_id"], name: "index_entity_group_relationships_on_entity_id_and_group_id", unique: true, using: :btree

  create_table "entity_property_relationships", force: true do |t|
    t.integer  "entity_id"
    t.integer  "property_id"
    t.integer  "group_id"
    t.integer  "order"
    t.string   "label"
    t.string   "value"
    t.integer  "visibility"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "group_property_relationships", force: true do |t|
    t.integer  "group_id"
    t.integer  "property_id"
    t.integer  "order"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "group_property_relationships", ["group_id", "property_id"], name: "index_group_property_relationships_on_group_id_and_property_id", unique: true, using: :btree
  add_index "group_property_relationships", ["group_id"], name: "index_group_property_relationships_on_group_id", using: :btree
  add_index "group_property_relationships", ["property_id"], name: "index_group_property_relationships_on_property_id", using: :btree

  create_table "groups", force: true do |t|
    t.string   "name"
    t.string   "default_label"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "groups", ["name"], name: "index_groups_on_name", unique: true, using: :btree

  create_table "properties", force: true do |t|
    t.string   "name"
    t.string   "units"
    t.string   "units_short"
    t.string   "default_label"
    t.string   "default_value"
    t.integer  "default_visibility"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "properties", ["name"], name: "index_properties_on_name", unique: true, using: :btree

Entity.rb

class Entity < ActiveRecord::Base
  has_many :entity_property_relationships
  has_many :entity_group_relationships
  has_many :properties, 
    through: :entity_property_relationships, 
    inverse_of: :entities
  has_many :groups, 
    through: :entity_group_relationships, 
    inverse_of: :entities
  validates :name, 
    presence: true
  #rest omitted
end

Property.rb

class Property < ActiveRecord::Base
  has_many :group_property_relationships
  has_many :entity_property_relationships
  has_many :entities, 
    through: :entity_property_relationships, 
    inverse_of: :properties
  has_many :groups, 
    through: :group_property_relationships, 
    inverse_of: :properties
  validates :name, presence: true
  #rest omitted
end

Group.rb

class Group < ActiveRecord::Base
  has_many :group_property_relationships
  has_many :entity_group_relationships
  has_many :entities, 
    through: :entity_group_relationships, 
    inverse_of: :groups
  has_many :properties, 
    through: :group_property_relationships, 
    inverse_of: :groups
  validates :name, 
    presence: true
  #rest omitted
end

entity_property_relationship.rb

class EntityPropertyRelationship < ActiveRecord::Base
  belongs_to :entity
  belongs_to :property
  validates :entity_id, 
    presence: true
  validates :property_id, 
    presence: true
  validates :order, 
    presence: :true
  #rest omitted
end

entity_group_relationship.rb

class EntityGroupRelationship < ActiveRecord::Base
  belongs_to :entity
  belongs_to :group 
  validates :entity_id, 
    presence: true
  validates :group_id, 
    presence: true
  validates :order, 
    presence: true
  #rest omitted
end

group_property_relationship.rb

class GroupPropertyRelationship < ActiveRecord::Base
  belongs_to :group
  belongs_to :property
  validates :group_id, 
    presence: true
  validates :property_id, 
    presence: true
  validates :order, 
    presence: true
  #rest omitted
end

Эта проблема

Поведение, которое я пытаюсь предотвратить, это когда property удалено, все EntityPropertyRelationships которые разделяют одно и то же Entity а также Group также удаляются. Это не так для GroupPropertyRelationships ни для EntityGroupRelationships и из всего, что я вижу и понимаю, эти отношения были настроены так, чтобы вести себя одинаково.

Я тестирую это с помощью rspec, вот несколько тестов.

Тест 1:

  it "should still own non-destroyed properties" do
    @entity = Entity.create!(name: "entity")

    @property1 = Property.create!(name: "property1")
    @property2 = Property.create!(name: "property2")

    @group = Group.create!(name: "group")
    @group.own!(@property1)
    @group.own!(@property2)

    @entity.own!(@group)

    @entity.utilizes?(@property1).should eq(true)
    @entity.utilizes?(@property2).should eq(true)

    @property1.destroy

    @entity.utilizes?(@property1).should eq(false)
    @entity.utilizes?(@property2).should eq(true)

    @group.owns?(@property1).should eq(false)
    @group.owns?(@property2).should eq(true)
  end

Тест 1 - это тест, который не проходит. entity должен еще utilize property - utilizes?() проверяет, что EntityPropertyRelationship существует между entity и данный property,

Тест 2

  it "should still own non-destroyed groups" do
    @entity = Entity.create!(name: "entity")

    @group1 = Group.create!(name: "group1")
    @group2 = Group.create!(name: "group2")

    @entity.own!(@group1)
    @entity.own!(@group2)

    @entity.owns?(@group1).should eq(true)
    @entity.owns?(@group2).should eq(true)

    @group1.destroy

    @entity.owns?(@group1).should eq(false)
    @entity.owns?(@group2).should eq(true)
  end

Тест 3

  it "should still utilize non-destroyed groups' properties" do
    @entity = Entity.create!(name: "entity")

    @group1 = Group.create!(name: "group1")
    @group2 = Group.create!(name: "group2")

    @property1 = Property.create!(name: "property1")
    @property2 = Property.create!(name: "property2")

    @group1.own!(@property1)
    @group2.own!(@property2)

    @entity.own!(@group1)
    @entity.own!(@group2)

    @entity.owns?(@group1).should eq(true)
    @entity.owns?(@group2).should eq(true)
    @entity.utilizes?(@property1).should eq(true)
    @entity.utilizes?(@property2).should eq(true)

    @group1.destroy

    @entity.owns?(@group1).should eq(false)
    @entity.owns?(@group2).should eq(true)
    @entity.utilizes?(@property1).should eq(false)
    @entity.utilizes?(@property2).should eq(true)
  end

Тест 2 и Тест 3 проходят нормально. Я не могу придумать, как насчет этих отношений оправдывает призыв уничтожить каждого EntityPropertyRelationship даже где property_id не является идентификатором свойства, которое будет уничтожено изначально. Есть ли что-то, что мне нужно изменить в отношениях, или есть способ, которым я мог бы предотвратить это с помощью destroy_callbacks?

1 ответ

Решение

Ой! Я только что нашел проблему. Я никогда не думал, что это будет там, где это было, вот почему потребовалось так много времени, чтобы найти. В моем GroupPropertyRelationshipsЯ имел after_destroy это разрушило бы EntityPropertyRelationships для каждого из этого Group's связанный Entities, Это должно просто разрушать EntityPropertyRelationships где group_id и property_id такие же как текущий GroupPropertyRelationship быть уничтоженным. Я заменил after_destroy код для GroupPropertyRelationship с:

after_destroy do |r|
  EntityPropertyRelationship.destroy_all group_id: r.group_id, property_id: r.property_id
end 

Это должно быть ошибка копирования-вставки.

Другие вопросы по тегам