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

One To Many (Polymorphic) relationship is not working with custom primaryKey #714

Open
LG0012 opened this issue Mar 24, 2021 · 4 comments
Open
Labels
bug Something isn't working

Comments

@LG0012
Copy link

LG0012 commented Mar 24, 2021

Describe the bug

Just imagine 2 models, Product and Attribute.

Product have One to Many (Polymorphic) relationship. Product model has own custom primaryKey (for example - uid).

The issue is that those attributes are inserted with wrong reference_id which is product.id, should be product.uid.

image

Steps to reproduce the bug

Product model

import { Model } from "@vuex-orm/core";
import Attribute from "./Attribute";

export default class Product extends Model {
  static entity = "cart_products";

  static primaryKey = 'uid';

  static fields() {
    return {
      uid: this.uid(),
      id: this.attr(null),
      sku: this.attr(""),
      name: this.string(""),
      attributes: this.morphMany(Attribute, "reference_id", "reference_type")
    };
  }
}

Attribute model

import { Model } from "@vuex-orm/core";

export default class Attribute extends Model {
  static entity = "cart_attributes";

  static fields() {
    return {
      id: this.attr(null),
      name: this.attr(""),
      value: this.attr(""),
      reference_id: this.attr(null),
      reference_type: this.attr(null),
      reference: this.morphTo("reference_id", "reference_type")
    };
  }
}


Insert data

const productObject = {
      id: 1001,
      sku: "QWERTY",
      name: "Product name",
      attributes: [
        {
          name: "attribute1",
          value: 50,
        },
        {
          name: "attribute2",
          value: 500,
        },
      ],
    };

    Product.insert({
      data: productObject,
    });

Get data

const products = Product.query().with("attributes").get();
console.log('products', products);

Expected behaviour

const products = Product.query().with("attributes").get();
console.log('products', products);

This part of code should return product object with all attributes and each attribute should contain product.uid value as reference_id, but in this case its always product.id (1001).

Versions

  • Vuex: 3.6.2
  • Vuex ORM: 0.36.3
  • Vue: 2.6.12

Link to minimal reproduction

Codesandbox: https://codesandbox.io/s/happy-dream-qbi0e?fontsize=14&hidenavigation=1&theme=dark

@LG0012
Copy link
Author

LG0012 commented Mar 27, 2021

Can someone fix this, please :)

@cuebit cuebit added the bug Something isn't working label Mar 30, 2021
@cuebit
Copy link
Member

cuebit commented Mar 30, 2021

I can confirm this is a bug.

The relation is attempting to acquire the primary key from the related entity (in this case Attribute), when it should be obtaining it from the owner (in this case Product). Since there is no such reference to the local key on the related entity, it obtains the default id attribute.

I don't know if there will be more releases permissible on this branch (though, the repo does state no new "features", not bug fixes). But while that is established, you can patch this issue with a temporary fix.

Create a plugin file and throw this in:

// MorphManyPatch.js

export default {
  install (components) {
    components.MorphMany.prototype.attach = function (key, record, data) {
      const relatedItems = data[this.related.entity]

      key.forEach((id) => {
        const relatedItem = relatedItems[id]

        relatedItem[this.id] = relatedItem[this.id] || this.model.getIdFromRecord(record)
        relatedItem[this.type] = relatedItem[this.type] || this.model.entity
      })
    }
  }
}

And install it before you install Vuex ORM to Vuex.

See updated sandbox https://codesandbox.io/s/eloquent-snowflake-6lrz7

@tintin10q
Copy link

Should this be added to the docs maybe? At least for now? I was stuck on this for quite a while, and in the end the only thing I needed to do was remove the custom primary key on the model. It is not something you expect and not something you will figure out without going to the issues on github.

@ricardov03
Copy link

I can confirm this is a bug.

The relation is attempting to acquire the primary key from the related entity (in this case Attribute), when it should be obtaining it from the owner (in this case Product). Since there is no such reference to the local key on the related entity, it obtains the default id attribute.

I don't know if there will be more releases permissible on this branch (though, the repo does state no new "features", not bug fixes). But while that is established, you can patch this issue with a temporary fix.

Create a plugin file and throw this in:

// MorphManyPatch.js

export default {
  install (components) {
    components.MorphMany.prototype.attach = function (key, record, data) {
      const relatedItems = data[this.related.entity]

      key.forEach((id) => {
        const relatedItem = relatedItems[id]

        relatedItem[this.id] = relatedItem[this.id] || this.model.getIdFromRecord(record)
        relatedItem[this.type] = relatedItem[this.type] || this.model.entity
      })
    }
  }
}

And install it before you install Vuex ORM to Vuex.

See updated sandbox https://codesandbox.io/s/eloquent-snowflake-6lrz7

Thanks, @cuebit, for taking the time to generate this solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants