GraphQL Rails 更新 API 时出现了 `Types::ItemType#id` 不存在的错误。

huangapple go评论50阅读模式
英文:

GraphQL Rails Update API getting `Types::ItemType#id`, which did not exist` error

问题

你有两个模型,Item和Artist,关系是Item属于Artist,而Artist有许多Items。

在app/models/item.rb文件中:

class Item < ApplicationRecord
  belongs_to :artist
end

在app/models/artist.rb文件中:

class Artist < ApplicationRecord
  has_many :items, dependent: :destroy
end

我创建了update_item.rb文件,放在app/graphql/update_item.rb中:

module Mutations
  class UpdateItem < BaseMutation
    
    type Types::ItemType

    argument :id, ID, required: true
    argument :title, String, required: true
    argument :description, String, required: true
    argument :image_url, String, required: true
    argument :artist_id, ID, required: true

    def resolve(id:, title:, description:, image_url:, artist_id:)
      Item.find(id).update!(title: title, description: description, image_url: image_url, artist_id: artist_id)
    end
  end
end

在app/graphql/types/mutation_type.rb中定义其mutation类型:

module Types
  class MutationType < Types::BaseObject
    field :update_item, mutation: Mutations::UpdateItem
  end
end

在GraphiQL web UI中写的mutation是:

mutation{
  updateItem(input: {
    id: 13,
    title: "gfnm",
    description: "vcbnm",
    imageUrl: "fgehyerjfdbgh",
    artistId: 8
  }){
      id
      title
  }
}

在数据库中已经更新了记录,但在rails服务器日志中出现上述错误。

英文:

I have two models Item and Artist, the relation is Item belongs to Artist and Artist has many Items.

app/models/item.rb

class Item &lt; ApplicationRecord
  belongs_to :artist
end

app/models/artist.rb

class Artist &lt; ApplicationRecord
    has_many :items, dependent: :destroy
end

I have created update_item.rb file inside app/graphql/update_item.rb

module Mutations
  class UpdateItem &lt; BaseMutation
    
    type Types::ItemType

    
    argument :id, ID, required: true
    argument :title, String, required: true
    argument :description, String, required: true
    argument :image_url, String, required: true
    argument :artist_id, ID, required: true

    
    def resolve(id:,title:,description:,image_url:, artist_id:)
      Item.find(id).update!(title: title, description: description, image_url: image_url, artist_id: artist_id)
    end
  end
end

define its mutation type in app/graphql/types/mutation_type.rb

module Types
  class MutationType &lt; Types::BaseObject
    field :update_item, mutation: Mutations::UpdateItem
  end
end

Mutatin which we have written in GraphiQL web UI is -

mutation{
  updateItem(input: {
    id: 13,
    title: &quot;gfnm&quot;,
    description: &quot;vcbnm&quot;,
    imageUrl: &quot;fgehyerjfdbgh&quot;,
    artistId: 8
  }){
      id
      title
  }
}

it has been updated the record in the database but after that getting error in the rails server log below -

Failed to implement Item.id, tried:

              - `Types::ItemType#id`, which did not exist
              - `TrueClass#id`, which did not exist
              - Looking up hash key `:id` or `&quot;id&quot;` on `true`, but it wasn&#39;t a Hash

              To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.

Could anyone please help me why getting the above error after updating the record?

答案1

得分: 1

According to these data in the GQL request,

{
   id
   title
}

it is expected that those fields (id and title) will be returned after the mutation is executed.

But there are no such fields defined in your mutation. What your mutation returns is the result of the resolve method, which is the result of the update! call, which is true. That's why you see the TrueClass#id, which did not exist error. It cannot extract the id and title fields from true.

The fields that you want to be returned must be listed with the field method. The result of the resolve method should be a hash including those fields.

module Mutations
  class UpdateItem &lt; BaseMutation
    
    type Types::ItemType

    argument :id, ID, required: true
    # ... The rest of arguments
    
    field :id, ID, null: false
    field :title, String, null: false

    def resolve(id:,title:,description:,image_url:, artist_id:)
      item = Item.find(id)
      item.update!(title: title, description: description, image_url: image_url, artist_id: artist_id)

      {
        id: item.id,
        title: item.title
      }
    end
  end
end

Here is another suggestion. As the best practice, the result of the mutation should be the updated record:

module Mutations
  class UpdateItem &lt; BaseMutation
    # ...

    field :item, Types::ItemType, null: false
    
    def resolve(id:,title:,description:,image_url:, artist_id:)
      item = Item.find(id)
      item.update!(title: title, description: description, image_url: image_url, artist_id: artist_id)

      {
        item: item
      }
    end
  end
end

Front-end:

mutation{
  updateItem(input: {
    id: 13,
    title: "gfnm",
    description: "vcbnm",
    imageUrl: "fgehyerjfdbgh",
    artistId: 8
  }){
      item { # requesting the updated record !!!
        id
        title
      }
  }
}

One more thing for you to figure out is how to handle error cases.

英文:

According to these data in the GQL request,

{
   id
   title
}

it is expected that those fields (id and title) will be returned after the mutation is executed.

But there are no such fields defined in your mutation. What your mutation returns is the result of the resolve method, which is the result of the update! call, which is true. That's why you see the
TrueClass#id, which did not exist error. It cannot extract the id and title fields from true.

The fields that you want to be returned must be listed with the field method. The result of the resolve method should be a hash including those fields.

module Mutations
  class UpdateItem &lt; BaseMutation
    
    type Types::ItemType

    argument :id, ID, required: true
    # ... The rest of arguments
    
    field :id, ID, null: false
    field :title, String, null: false

    def resolve(id:,title:,description:,image_url:, artist_id:)
      item = Item.find(id)
      item.update!(title: title, description: description, image_url: image_url, artist_id: artist_id)

      {
        id: item.id,
        title: item.title
      }
    end
  end
end

Here is another suggestion. As the best practice, the result of the mutation should be the updated record:

module Mutations
  class UpdateItem &lt; BaseMutation
    # ...

    field :item, Types::ItemType, null: false
    
    def resolve(id:,title:,description:,image_url:, artist_id:)
      item = Item.find(id)
      item.update!(title: title, description: description, image_url: image_url, artist_id: artist_id)

      {
        item: item
      }
    end
  end
end

Front-end:

mutation{
  updateItem(input: {
    id: 13,
    title: &quot;gfnm&quot;,
    description: &quot;vcbnm&quot;,
    imageUrl: &quot;fgehyerjfdbgh&quot;,
    artistId: 8
  }){
      item { # requesting the updated record !!!
        id
        title
      }

  }
}

One more thing for you to figure out is how to handle error cases.

huangapple
  • 本文由 发表于 2023年5月10日 20:08:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218237.html
  • graphql
  • ruby-on-rails