I am creating an app where there are three main models and relationships between them about which I need to track some properties:
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
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
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
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
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
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
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
The behavior that is happening that I am trying to prevent is when a property
is deleted, all EntityPropertyRelationships
that share the same Entity
and Group
are also deleted. This isn't the case for GroupPropertyRelationships
, nor for EntityGroupRelationships
, and from everything I can see and understand, these relationships have been set up to behave identically.
I am testing this with rspec, here are some tests.
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
Test 1 is the test that fails. The entity
should still utilize
the property
- utilizes?()
checks that an EntityPropertyRelationship
exists between the entity
and the given property
.
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
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
Test 2 and Test 3 pass fine. I can not seem to pin down what about these relationships warrants a call to destroy each EntityPropertyRelationship
, even where property_id
isn't the id of the property being destroyed initially. Is there something I need to change about the relationships, or is there a way I could prevent this with destroy_callbacks?
Ouch! I just found the issue. I never thought it would be where it was, that's why it took so long to find. In my GroupPropertyRelationships
, I had an after_destroy
that would destroy the EntityPropertyRelationships
for each of that Group's
associated Entities
. It should just be destroying the EntityPropertyRelationships
where the group_id
and the property_id
are the same as the current GroupPropertyRelationship
being destroyed. I replaced the after_destroy
code for the GroupPropertyRelationship
with:
after_destroy do |r|
EntityPropertyRelationship.destroy_all group_id: r.group_id, property_id: r.property_id
end
That must have been a copy-paste error.