-
Notifications
You must be signed in to change notification settings - Fork 465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setting #parent_id with nested attributes can result in corrupted #ancestry #423
Comments
@astyagun Have you created a test for this? node1.parent_id = node2.id
node2.parent_id = node3.id
node1.save
node2.save
Wonder if there is a way to enforce a good save order. |
@kbrock To reproduce the problem a test like this could be used: describe '#update nodes using nested attributes' do
subject(:update) { instance.update nodes_attributes: nodes_attributes }
let(:instance) { create :tree }
context 'when nesting nodes several levels deep' do
let!(:node_one) { create :node, tree: instance }
let!(:node_two) { create :node, tree: instance }
let!(:node_three) { create :node, tree: instance }
let :nodes_attributes do
# Order of hashes is significant
[
{ id: node_two.id, parent_id: node_one.id },
{ id: node_three.id, parent_id: node_two.id }
]
end
it 'saves #ancestry of the most nested node correctly' do
update
expect(node_three.reload.ancestry).to eq "#{node_one.id}/#{node_two.id}"
end
end
end |
Reordering works indeed, I've tried it in the test above. But using |
More about describe '#update nodes using nested attributes' do
subject(:update) { instance.update nodes_attributes: nodes_attributes }
let(:instance) { create :tree }
context 'when nesting nodes several levels deep' do
let!(:node_one) { create :node, tree: instance }
let!(:node_two) { create :node, tree: instance }
let!(:node_three) { create :node, tree: instance }
let(:tree_nodes_association) { instance.association :nodes }
let(:tree_nodes) { tree_nodes_association.target }
let(:node_one_from_association) { tree_nodes.detect { |node| node.id == node_one.id } }
let(:node_two_from_association) { tree_nodes.detect { |node| node.id == node_two.id } }
let :nodes_attributes do
# Order of hashes is significant
[
{ id: node_two.id, parent: node_one_from_association },
{ id: node_three.id, parent: node_two_from_association }
]
end
before { tree_nodes_association.load_target }
it 'saves ancestry of the most nested node correctly' do
update
expect(node_three.reload.ancestry).to eq "#{node_one.id}/#{node_two.id}"
end
end
end No luck, still fails. This is not the way to get same instances everywhere, probably. |
As I'm sure you already know, The problem is when you set a There are then 2 copies of the record in memory, and when you update one, the other is wrong / stale. A working algorithm would be to set the parent nodes instead of the parent_id nodes. There may be a way to change ancestry to delay the lookup of the parent record from the |
Another option is to sort nodes before they are submitted into |
Given:
has_many :nodes
accepts_nested_attributes_for :nodes
has_ancestry
#parent_id
attributesThe problem occurs, for example, when:
#id
attributes respectively'1'
,'2'
and'3'
)Then:
#parent_id
attribute#ancestry
attribute is used to assign#ancestry
of a child node.#ancestry
of#id
of node one,'1'
, which is correct#ancestry
of#id
of node two only,'2'
. Which is incorrect as it should have IDs of all chain of parent nodes in its#ancestry
attribute. What it should be assigned is'1/2'
.And this results in corrupted
#ancestry
attribute of node three and it disappears from the nodes tree.The text was updated successfully, but these errors were encountered: