Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Active Model Serializer include in controller not injecting has many relationship in included parameter

I'm seeing a strange behaviour regarding rails 5, active model serializer and the json-api adapter.

Given the following User model with the Rolify gem:

class User < ActiveRecord::Base
  #
  # Gem Includes
  #
  rolify


  # Include devise modules.
  devise :database_authenticatable,
      :recoverable, :rememberable, :trackable, :validatable
  include DeviseTokenAuth::Concerns::User

  #
  # Callbacks
  #
  after_create :assign_default_role

  #
  # Attributes
  #
  attr_accessor :remote_image

  #
  # Validations
  #
  validates :name, presence: true, length: {in: 1..100}
  validates :last_name, presence: true, length: {in: 1..100}
  validates :role_ids, presence: true, on: :update

  #
  # Relations
  #
  belongs_to :current_scenario, class_name: "Scenario"


  #
  # Private Instance Methods
  #
  def assign_default_role
    self.add_role(:user) if self.roles.blank?
  end

end

and the following controller code:

def show
  @user = User.find(params[:id])
  authorize @user
  render json: @user, include: ['roles'], status: :ok
end

As you can see, I'm including the roles relationship to be rendered as part of the json api response, with json-api adapter format.

FYI, the UserSerializer:

class UserSerializer < ActiveModel::Serializer
  #
  # Attributes
  #
  attributes :id, :email, :name, :last_name, :image_url, :image_thumb_url, :created_at, :updated_at, :current_scenario_id, :last_sign_in_at

  #
  # Relations
  #
  has_one :current_scenario
  has_many :roles

  #
  # Methods
  #
  def image_url
    object.image_url
  end

  def image_thumb_url
    object.image_url(:thumb)
  end
end

When retrieving the json response, I get the following:

{
  "data": {
    "id":"2",
    "type":"users",
    "attributes": {
      "email":"[email protected]", ...
    },
    "relationships": {
      "current-scenario": {
        "data": {
          "id":"204",
          "type":"scenarios"
        }
      },
      "roles": {
        "data": [
          {
            "id":1,
            "name":"user",
            "resource-type":null,
            "resource-id":null,
            "created-at":"2017-01-23T10:27:08.707-03:00",
            "updated-at":"2017-01-23T10:27:08.707-03:00"
          },
          {
            "id":2,
            "name":"admin",
            "resource-type":null,
            "resource-id":null,
            "created-at":"2017-01-24T09:40:53.020-03:00",
            "updated-at":"2017-01-24T09:40:53.020-03:00"
          }
        ]
      }
    }
  }
}

As you can see, the included relationship roles with all its attributes is inside the relationships fragment of the json-api response. Shouldn't the roles data be inside the included fragment, which by the way is missing? Moreover inside the relationship fragment roles should appear only as a reference like: {relationships: {roles: [{id: "1", type: "role"}, {id: "2", type: "role"}]} am I wrong?

To contrast this, look what happens when also including the current_scenario relationship:

{
  "data": {
    "id":"2",
    "type":"users",
    "attributes": {
      "email":"[email protected]",
      "name":"Tomás",
      "last-name":"Alvarez", 
      ...
    },
    "relationships": {
      "current-scenario": {
        "data": {
          "id":"204",
          "type":"scenarios"
        }
      },
      "roles": {
        "data": [
          {
            "id":1,
            "name":"user",
            "resource-type":null,
            ...
          }
        ]
      }
    },
    "included": [
      {
        "id":"204",
        "type":"scenarios",
        "attributes": {
          "name":"Scenario reload II",
          "description":null,
          "created-at":"2017-04-18T11:55:35.242-03:00",
          "updated-at":"2017-04-18T11:55:35.242-03:00"
        },
        "relationships": {
          "scenario-stocks": {
            "data":[]
          }
        }
      }
    ]
  }
}

See how now the included fragment appears with all the information about current_scenario and only the reference to current_scenario is added to the relationships fragment. Is this because roles is a has_many relationship in the active model serializer while current_scenario is a belongs_to ? Am I understanding wrong the json-api adapter specification?

Many thanks!

like image 322
tommyalvarez Avatar asked Nov 19 '22 22:11

tommyalvarez


1 Answers

Ouch. The inconsistency in the JSON-API response was because i forgot to add a Role model serializer in the backend side (Rails 5). This is the json response now, which is what i was looking for:

{
"data": {
    "id": "2",
    "type": "users",
    "attributes": {
        "email": "[email protected]",
        "name": "Tomás",
        "last-name": "Alvarez",
        "image-url": "http://localhost:3001/uploads/user/image/2/05a4dc7.jpg",
        "image-thumb-url": "http://localhost:3001/uploads/user/image/2/thumb_05a4dc7.jpg",
        "created-at": "2017-01-23T10:39:12.485-03:00",
        "updated-at": "2017-04-25T16:32:14.610-03:00",
        "current-scenario-id": 204,
        "last-sign-in-at": "2017-04-25T16:29:03.559-03:00"
    },
    "relationships": {
        "current-scenario": {
            "data": {
                "id": "204",
                "type": "scenarios"
            }
        },
        "roles": {
            "data": [{
                "id": "1",
                "type": "roles"
            }, {
                "id": "2",
                "type": "roles"
            }]
        }
    }
},
"included": [{
    "id": "204",
    "type": "scenarios",
    "attributes": {
        "name": "Scenario reload II",
        "description": null,
        "created-at": "2017-04-18T11:55:35.242-03:00",
        "updated-at": "2017-04-18T11:55:35.242-03:00"
    },
    "relationships": {
        "scenario-stocks": {
            "data": []
        }
    }
}, {
    "id": "1",
    "type": "roles",
    "attributes": {
        "name": "user"
    }
}, {
    "id": "2",
    "type": "roles",
    "attributes": {
        "name": "admin"
    }
}]

}

like image 148
tommyalvarez Avatar answered Jan 03 '23 03:01

tommyalvarez