{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/relay/issues/782","repository_url":"https://api.github.com/repos/facebook/relay","labels_url":"https://api.github.com/repos/facebook/relay/issues/782/labels{/name}","comments_url":"https://api.github.com/repos/facebook/relay/issues/782/comments","events_url":"https://api.github.com/repos/facebook/relay/issues/782/events","html_url":"https://github.com/facebook/relay/issues/782","id":130368345,"number":782,"title":"Fragment issue when committing Mutation","user":{"login":"danielgriese","id":927132,"avatar_url":"https://avatars.githubusercontent.com/u/927132?v=3","gravatar_id":"","url":"https://api.github.com/users/danielgriese","html_url":"https://github.com/danielgriese","followers_url":"https://api.github.com/users/danielgriese/followers","following_url":"https://api.github.com/users/danielgriese/following{/other_user}","gists_url":"https://api.github.com/users/danielgriese/gists{/gist_id}","starred_url":"https://api.github.com/users/danielgriese/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielgriese/subscriptions","organizations_url":"https://api.github.com/users/danielgriese/orgs","repos_url":"https://api.github.com/users/danielgriese/repos","events_url":"https://api.github.com/users/danielgriese/events{/privacy}","received_events_url":"https://api.github.com/users/danielgriese/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":21,"created_at":"2016-02-01T13:57:04Z","updated_at":"2016-02-23T06:34:54Z","closed_at":null,"body":"Hi there,\r\n\r\nI have just implemented a new feature in our product using Relay and it worked like a charm so far. Thank you for your awesome work and for open sourcing Relay!\r\n\r\nUnfortunately I have encountered a tricky issue, that I currently do not know how to circumvent and if it is a bug in relay or if my schema is just programmed in a stupid way. Both options are valid at this point in time... :D\r\n\r\n### Situation\r\nI have page showing a \"Claim\" that refers to a \"Medium\". This claim has an applied \"Policy\" that can be changed by a mutation. All these types implement a common Resource interface.\r\nThe shortened Schema looks like this.\r\n\r\n```\r\ninterface Resource {\r\n  id: ID!\r\n  name: String\r\n}\r\n\r\ntype Claim implements Node, Resource {\r\n  id: ID!\r\n  name: String\r\n  medium: Medium\r\n  policy: Policy\r\n}\r\n\r\ntype Medium implements Node, Resource {\r\n  id: ID!\r\n  name: String\r\n  remoteUrl: String\r\n}\r\n\r\ntype Policy implements Node, Resource {\r\n  id: ID!\r\n  name: String\r\n}\r\n```\r\n\r\nThe mutation is described as this:\r\n\r\n```\r\ntype Mutation {\r\n  updateClaimPolicy(input: UpdatePolicyInput!): UpdatePolicyPayload\r\n}\r\n\r\ninput UpdatePolicyInput {\r\n  id: ID!\r\n  policy: String!\r\n  clientMutationId: String!\r\n}\r\n\r\ntype UpdatePolicyPayload {\r\n  claim: Claim\r\n  clientMutationId: String!\r\n}\r\n```\r\n\r\nThe client side mutation code:\r\n```\r\nexport default class UpdateClaimPolicyMutation extends Relay.Mutation {\r\n\r\n  // we depend on the claim id, so make sure we get it\r\n  static fragments = {\r\n    claim: () => Relay.QL`\r\n      fragment on Claim {\r\n        id\r\n      }\r\n    `,\r\n  };\r\n\r\n  getMutation() {\r\n    return Relay.QL`mutation {updateClaimPolicy}`;\r\n  }\r\n\r\n  getVariables() {\r\n    return { id: this.props.claim.id, policy: this.props.policy._id };\r\n  }\r\n\r\n  /**\r\n  * All that could change...\r\n  * For now this is only the claims policy and the updater\r\n  */\r\n  getFatQuery() {\r\n    return Relay.QL`\r\n      fragment on UpdatePolicyPayload {\r\n        claim {\r\n          policy\r\n          updatedOn\r\n          updatedBy\r\n        }\r\n      }\r\n    `;\r\n  }\r\n\r\n  // tell relay how to react to the payload...\r\n  // in this case, update the claim\r\n  getConfigs() {\r\n    return [{\r\n      type: 'FIELDS_CHANGE',\r\n      fieldIDs: {\r\n        claim: this.props.claim.id,\r\n      },\r\n    }];\r\n  }\r\n\r\n}\r\n```\r\n\r\n\r\nThe displaying container has the following (shortened) fragment:\r\n```\r\nclaim: () => Relay.QL`\r\n      fragment on Claim {\r\n        _id\r\n        medium {\r\n          name\r\n        }\r\n        policy {\r\n          name\r\n        }\r\n    }\r\n    `,\r\n```\r\n\r\nSo far everything is fine. I can navigate to the page and update the policy by the given mutation.\r\n\r\n### Problem\r\nI have another page showing a list of occurred activities in the system.\r\nAn activity has a generic target that can be any type implementing the Resource interface.\r\n```\r\ntype Activity implements Node {\r\n  id: ID!\r\n  time: DateTime\r\n  user: User\r\n  action: String\r\n  target: Resource\r\n}\r\n```\r\n\r\nAs I need to render the target differently depending on the type, I need to query for different data for different objects.\r\n```\r\nconst mediumFragment = Relay.QL`\r\n  fragment on Medium {\r\n    name\r\n    remoteUrl\r\n  }\r\n`;\r\n\r\nconst claimFragment = Relay.QL`\r\n  fragment on Claim {\r\n    medium {\r\n      ${mediumFragment}\r\n    }\r\n  }\r\n`;\r\n\r\nexport default Relay.createContainer(ActivityLine, {\r\n  fragments: {\r\n    activity: () => Relay.QL`\r\n      fragment on Activity {\r\n        id\r\n        time\r\n        user {\r\n          _id\r\n        \tfullName\r\n        }\r\n        action\r\n        target {\r\n          id\r\n          __typename\r\n          name\r\n          ${mediumFragment}\r\n          ${claimFragment}\r\n        }\r\n      }\r\n    `,\r\n  },\r\n});\r\n```\r\n\r\nI need both fragments, as the target can either be a Medium directly or a Claim whos medium information I want to get as well.\r\n\r\nThis still works fine!\r\nBut when I show an activity with a claim (and expanded Medium) and then navigate to the claim edit-page (which still works fine btw) and execute the change policy mutation, I get the following error:\r\n\r\n> Fragment \\\"F3\\\" cannot be spread here as objects of type \\\"Claim\\\" can never be of type \\\"Medium\\\".\r\n\r\nIn the network tab, I see the request to the server asking for a Fragment on Medium, even though the medium is not in the mutation or its fat query.\r\n\r\n>   \"mutation UpdateClaimPolicyMutation($input_0:UpdatePolicyInput!){updateClaimPolicy(input:$input_0){clientMutationId,...F5}} fragment F0 on User{_id,fullName,id} fragment F1 on Claim{id} fragment F2 on Claim{policy{_id,name,id},id} fragment F3 on Medium{id} fragment F4 on Node{id} fragment F5 on UpdatePolicyPayload{claim{policy{_id,id},updatedBy{id,...F0},updatedOn,id,...F1,...F2,...F3,...F4,policy{_id,id},updatedBy{id,...F0},updatedOn,id}}\"\r\n\r\n### Random Guessing\r\nI guess the issue is that Relay is internally still tracking the combined queries from activities and the claim edit page and is somehow mixing up the requested fragments.\r\nOf course a claim can never be a Medium! But I never asked to do that. I asked to get a Medium-Fragment on a Resource earlier, which might be a Claim. But not both at the same time of course.\r\n\r\nSo this seems kind of strange to me. Why would it try to apply the Medium Fragment on the Claim.\r\n\r\n- It only happens when I load the activities first (my guess is tracking of the nodes/queries). \r\n\r\n- And only when I make a mutation. \r\n\r\nQuerying the data works without any issue and making the mutation without accessing the activities first also works smoothly.\r\n\r\nDo you have any possibilities to replicate this issue or have any comments how this can be avoided?\r\nI wouldn't have a problem to simply \"kill\" tracked queries from my Activity-List page when I navigate away from it. I do not need any caching or anything else here. But I guess this is not the root-cause in this issue.\r\n\r\nThank you very much in advance for your support and kind regards,\r\nDaniel\r\n "},"comment":{"url":"https://api.github.com/repos/facebook/relay/issues/comments/187568438","html_url":"https://github.com/facebook/relay/issues/782#issuecomment-187568438","issue_url":"https://api.github.com/repos/facebook/relay/issues/782","id":187568438,"user":{"login":"josephsavona","id":6425824,"avatar_url":"https://avatars.githubusercontent.com/u/6425824?v=3","gravatar_id":"","url":"https://api.github.com/users/josephsavona","html_url":"https://github.com/josephsavona","followers_url":"https://api.github.com/users/josephsavona/followers","following_url":"https://api.github.com/users/josephsavona/following{/other_user}","gists_url":"https://api.github.com/users/josephsavona/gists{/gist_id}","starred_url":"https://api.github.com/users/josephsavona/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/josephsavona/subscriptions","organizations_url":"https://api.github.com/users/josephsavona/orgs","repos_url":"https://api.github.com/users/josephsavona/repos","events_url":"https://api.github.com/users/josephsavona/events{/privacy}","received_events_url":"https://api.github.com/users/josephsavona/received_events","type":"User","site_admin":false},"created_at":"2016-02-23T06:34:54Z","updated_at":"2016-02-23T06:34:54Z","body":"@NevilleS Yes, the general shape of the solution - wrapping tracked fields in conditioning fragments - is correct. It isn't exactly clear what the most efficient way to determine the fragment type to wrap the field in (perhaps we have to store the parent field type of a fragment when we track it?). \r\n\r\ncc @wincent who is focusing on simplifying mutations - he might have more ideas here."}}