如何使用jsonapi资源修复API,该资源以不匹配类型响应并且不允许我创建记录?

时间:2017-06-20 09:47:23

标签: rails-activerecord rails-api json-api legacy-database jsonapi-resources

每次我想创建一个新项目时,我的API中的Mismatch类型都有问题。

它发生在两个地方:

  1. 当我尝试发布新项目时
  2. POST http://localhost:8060/datasets/

        {
        "data": {
                "type": "datasets",
                "attributes": {
                    "doi": "10.5259/2008120816KAKA",
                    "version": 0,
                    "is-active": "1",
                    "datacentre": 201
                }
        }
    

    响应

        "errors": [
        {
            "title": "Internal Server Error",
            "detail": "Internal Server Error",
            "code": "500",
            "status": "500",
            "meta": {
                "exception": "Datacentre(#23863440) expected, got 201 which is an instance of Fixnum(#4211740)",
                "backtrace": [
                    "/usr/local/rvm/gems/ruby-2.3.3/gems/activerecord-5.1.1/lib/active_record/associations/association.rb:239:in `raise_on_type_mismatch!'",
                    "/usr/local/rvm/gems/ruby-2.3.3/gems/activerecord-5.1.1/lib/active_record/associations/belongs_to_association.rb:11:in `replace'",
                    "/usr/local/rvm/gems/ruby-2.3.3/gems/activerecord-5.1.1/lib/active_record/associations/singular_association.rb:15:in `writer'",
                    "/usr/local/rvm/gems/ruby-2.3.3/gems/activerecord-5.1.1/lib/active_record/associations/builder/association.rb:119:in `datacentre='"
    
    1. 我可以在访问项目的关系时看到它发生。例如,这是一个GET响应:
    2. 获取http://localhost:8060/datasets/

          {
          "data": [
              {
                  "id": "5",
                  "type": "datasets",
                  "links": {
                      "self": "http://localhost:8060/datasets/5"
                  },
                  "attributes": {
                      "created": "2011-03-02T16:41:20.000Z",
                      "doi": "10.5259/20070410230000/HTTP://www.STAFFSPASTTRACK.ORG.UK/EXHIBIT/CRIMEANDPUNISHMENT/IMAGEPAGE/ZERO.HTM",
                      "version": 0,
                      "is-active": "",
                      "updated": "2011-03-02T16:41:20.000Z",
                      "datacentre": "#<Datacentre:0x000000033389b8>",
                      "deposited": "2012-07-31T09:12:37.000Z"
                  },
                  "relationships": {
                      "datacentre": {
                          "links": {
                              "self": "http://localhost:8060/datasets/5/relationships/datacentre",
                              "related": "http://localhost:8060/datasets/5/datacentre"
                          }
                      }
                  }
              }
      

      您可以看到datacentre(foreign_key)属性如何显示为模型数据中心的对象类型。如果我尝试访问该模型http://localhost:8060/datasets/5/datacentre的相关性,我会得到以下内容:

      {
      * errors: [
      * {
      * title: "Internal Server Error",
      * detail: "Internal Server Error",
      * code: "500",
      * status: "500",
      * meta: {
      * exception: "Unknown source type #<Datacentre id: 10015, comments: "", contact_email: "andrew.jackson@bl.uk", contact_name: "Andy Jackson", created: "2010-12-14 22:05:32", doi_quota_allowed: 50000, doi_quota_used: 17, domains: "webarchive.org.uk", is_active: "\x01", name: "Web Archive Programme at BL", password: "98583c1bf114bfe80105f906d800e05325307f06b93ccee6b6...", role_name: "ROLE_DATACENTRE", symbol: "BL.WAP", updated: "2012-02-17 11:49:01", version: 2, allocator: 106, experiments: nil>",
      * backtrace: [
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/resource_serializer.rb:267:in `top_level_source_key'",
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/resource_serializer.rb:47:in `block in serialize_to_hash'",
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/resource_serializer.rb:47:in `map'",
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/resource_serializer.rb:47:in `serialize_to_hash'",
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/response_document.rb:109:in `results_to_hash'",
      * "/usr/local/rvm/gems/ruby-2.3.3/gems/jsonapi-resources-0.9.0/lib/jsonapi/response_document.rb:12:in `contents’”,
      

      我认为问题在于API期望错误的对象类型。当它应该期待 DatacentreResource 时,它期待数据中心

      我的设置如下:

      • 我有一个Legacy数据库,它不遵循命名表和foreign_keys的ActiveRecord约定。
      • 表格是单数,foreign_keys没有_id后缀。
      • 我遇到问题的表/模型有one_to_many关系。
      • 该关系为datacentre has_many datasets
      • 我正在使用jsonapi-resources和rails 5 api-only

      数据中心模型

      class Datacentre < ApplicationRecord
        self.table_name = "datacentre"
        alias_attribute :allocator_id, :allocator
        has_and_belongs_to_many :prefixes, class_name: 'Prefix', join_table: "datacentre_prefixes", foreign_key: :prefixes, association_foreign_key: :datacentre
        belongs_to :allocator, class_name: 'Allocator', foreign_key: :allocator
        has_many :datasets
      end
      

      数据集模型

      class Dataset < ApplicationRecord
        self.table_name = "dataset"
        alias_attribute :datacentre_id, :datacentre
        belongs_to :datacentre, class_name: 'Datacentre', foreign_key: :datacentre
      end
      

      数据中心资源

      class DatacentreResource < JSONAPI::Resource
        model_name 'Datacentre'
        model_hint model: Datacentre
        attributes  :comments, :contact_email, :contact_name, :created, :doi_quota_allowed, :doi_quota_used, :domains, :is_active, :name, :password, :role_name, :symbol,   
           :updated, :version, :experiments, :allocator
        has_many :datasets
        has_many :prefixes
        has_one :allocator, class_name: 'Allocator', foreign_key: :allocator
      end
      

      数据集资源

      class DatasetResource < JSONAPI::Resource
        model_name 'Dataset'
        model_hint model: Dataset
        attributes  :created, :doi, :version, :is_active,  :updated, :datacentre
        attribute :deposited
        has_one :datacentre, class_name: "Datacentre", foreign_key: :datacentre
      end
      

      到目前为止,我通过在数据集资源中修改datacentre及其别名datacentre_id的方法来解决第一个问题(即访问关系)

       def datacentre(context=nil)
        DatacentreResource.find_by_key(@model.datacentre.id)
       end
      
        def datacentre_id()
          @model.datacentre.id
       end
      

      但这并不能解决POST问题。

1 个答案:

答案 0 :(得分:0)

我认为这是导致错误的原因

class Dataset < ApplicationRecord
  self.table_name = "dataset" 
  alias_attribute :datacentre_id, :datacentre
  belongs_to :datacentre, class_name: 'Datacentre', foreign_key: :datacentre
end

datacentre_iddatacentre有别名,因此它会返回并回复对象datacentre,而不是datacentre_id

如果你删除这一行,可能会有什么问题