0

I have a problem with Mismatch types in my API everytime I want to create a new item.

It happens in 2 places:

  1. when I try to POST a new item

POST http://localhost:8060/datasets/

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

Response

    "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. I can see it happening when accessing the relationships of an item. For example this is a a GET response:

GET 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"
                    }
                }
            }
        }

You can see how the datacentre (foreign_key) attribute is presented as an object type of the Model Datacentre. If I try to access the relantship to that model http://localhost:8060/datasets/5/datacentre I get the following:

{
* 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’”,

I think the problem is that the API is expecting the wrong type of object. It’s expecting Datacentre when it should be expecting DatacentreResource.

My setup is as follows:

  • I have a Legacy database that doesn’t follow the ActiveRecord conventions for naming tables and foreign_keys.
  • Tables are singular and foreign_keys do not have the _id suffix.
  • The tables/models in which I have the problem have one_to_many relationship.
  • The relationship being a datacentre has_many datasets.
  • I am using jsonapi-resources and rails 5 api-only.

Datacentre Model

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

Dataset Model

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

Datacentre Resource

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

Dataset Resource

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

So far I have got around the first problem (i.e. accessing the relationship) by modifying the methods for datacentre and its alias datacentre_id in the Dataset Resource

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

  def datacentre_id()
    @model.datacentre.id
 end

But this doesn’t solve the POST problem.

kriztean
  • 229
  • 3
  • 13

1 Answers1

0

I think this is the thing that cause the error

in

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

datacentre_id and datacentre are aliased so it gives back and object datacentre back in response instead of datacentre_id

probably it will wokr if you remove this line

beniutek
  • 1,672
  • 15
  • 32