Skip to content
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

Hashdiff does not see change if nested object is updated in place due to same reference value in resource object and original_state #1331

Open
kaarelss opened this issue Jul 22, 2024 · 1 comment
Labels

Comments

@kaarelss
Copy link
Contributor

Issue summary

HashDiff does not see change if nested resource object is updated in place. When resource object is created with #create_instance method, it adds value to both resource and to the original_state. If you update the object in place, the change will be reflected in original_state aswell which is wrong.

Expected behavior

All values in original_state should be duplicates, not references.

Steps to reproduce the problem

  1. Install gems gem install shopify_api rspec
  2. Create ruby script with the content below
  3. Execute script with rspec bundle exec rspec ${script_file_name}
it "should reproduce issue with reference value in original_state" do
    resource_hash = {
        name: "#111",
        line_items: [
          { title: "One", price: 100, quantity: 1 },
        ],
        shipping_address: {
          first_name: "John",
          last_name: "Doe",
          address_1: "Freedom street",
        },
    }.values_as_hash

    draft_order = ShopifyAPI::DraftOrder.new(from_hash: resource_hash)
    draft_order.save!
    expect(draft_order.shipping_address["first_name"]).to eq("John")

    # This changes original_state which is wrong
    draft_order.shipping_address["first_name"] = "Tom"
    draft_order.save!

    expect(draft_order.shipping_address["first_name"]).to eq("Tom")

    # It is only possible to update it by setting whole object like this
    updated_address = draft_order.shipping_address.values_as_hash
    updated_address[:first_name] = "Tom"
    draft_order.shipping_address = updated_address
    draft_order.save!

    expect(draft_order.shipping_address["first_name"]).to eq("Tom")
end

This is our current workaround to fix this issue.

module ShopifyAPI
  module Rest
    module BaseExtension

      def create_instance(data:, session:, instance: nil)
        result = super
        result.original_state = result.original_state.deep_dup

        result
      end

    end
  end
end

ShopifyAPI::Rest::Base.singleton_class.prepend(ShopifyAPI::Rest::BaseExtension)

This is where the actual issue is happening:

else
instance.public_send("#{attribute}=", value)
instance.original_state[attr_sym] = value
end

@Arkham Arkham added the bug label Jul 23, 2024
@Arkham
Copy link

Arkham commented Jul 23, 2024

Hey 👋 ,

thanks for reporting this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants