Skip to content
This repository has been archived by the owner on Jan 25, 2019. It is now read-only.

How to use ToOneRelationship() and serializeAs() on the same attribute? #175

Open
gaetanm opened this issue Mar 28, 2017 · 7 comments
Open

Comments

@gaetanm
Copy link

gaetanm commented Mar 28, 2017

You will understand just by looking at my class:

import Spine

class Menu: Resource {
    var nbrOfRecipes: Int?
    var userID: User?
    var recipes: LinkedResourceCollection?
    
    override class var resourceType: ResourceType {
        return "menus"
    }
    
    override class var fields: [Field] {
        return fieldsFromDictionary([
            "nbrOfRecipes": Attribute().serializeAs("nb-recipes"),
            "userID": Attribute().serializeAs("user-id"),
            "userID": ToOneRelationship(User.self),
            "recipes": ToManyRelationship(Recipe.self)
            ])
    }
}

As you can guess, this result in a fatal error: Dictionary literal contains duplicate keys.

How to do to apply both ToOneRelationship(User.self) and Attribute().serializeAs("user-id") on the same attribute?

@gaetanm gaetanm changed the title How to use ToOneRelationship() and serializeAs() on the same attribute How to use ToOneRelationship() and serializeAs() on the same attribute? Mar 28, 2017
@markst
Copy link

markst commented Apr 4, 2017

@gaetanm why do you need to apply both attributes on the same property?
why not have two properties one for the user relationship & the other for user-id?

class Menu: Resource {
    var nbrOfRecipes: Int?
    var userID: String?
    var user: User?

@markst
Copy link

markst commented Apr 4, 2017

Perhaps you could provide an example of your response JSON to make it clear?

@gaetanm
Copy link
Author

gaetanm commented Apr 6, 2017

I don't know enough about how Spine works internally to know that it was possible to use 2 properties for the same JSON data. Interesting!

About the JSON response, it's like this:

"data": {
    "id": "4",
    "type": "menus",
    "attributes": {
      "nb-recipes": 4,
      "created-at": "2016-11-27 19:50:07",
      "user-id": 1
    }

By using 2 properties like you showed me, I now have an assertion failure:

Resource of type menus does not contain a field named user-id

My query is:

var query = Query(resourceType: Menu.self)
query.whereAttribute("user-id", equalTo: userID!)

My class is now:

class Menu: Resource {
    var nbrOfRecipes: Int?
    var user: User?
    var userID: String?
    var recipes: LinkedResourceCollection?
    
    override class var resourceType: ResourceType {
        return "menus"
    }
    
    override class var fields: [Field] {
        return fieldsFromDictionary([
            "nbrOfRecipes": Attribute().serializeAs("nb-recipes"),
            "userID": Attribute().serializeAs("user-id"),
            "user": ToOneRelationship(User.self),
            "recipes": ToManyRelationship(Recipe.self)
            ])
    }
}

It's really a black box for me. Do I have this error because of those 2 properties?

@markst
Copy link

markst commented Apr 7, 2017

to resolve the error:

Resource of type menus does not contain a field named user-id
You'll need to pass the class property name into the query:

query.whereAttribute("userID", equalTo: userID!)

Spine will perform the appropriate transform/formatting from property name to field name as described in serializeAs().

@markst
Copy link

markst commented Apr 7, 2017

@gaetanm please see examples on http://jsonapi.org/ for how relationships responses should look. I think your JSON should look more like this:

"data": [{
    "id": "4",
    "type": "menus",
    "attributes": {
      "nb-recipes": 4,
      "created-at": "2016-11-27 19:50:07",
    },
    "relationships": {
      "user": {
        "data": { "type": "users", "id": "1" }
      },
    }
  }],
  "included": [{
    "type": "users",
    "id": "1",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
    },

Which includes the relationships properties & also the associated included object

Without needing the additional user-id attribute, you can access this data through the Resource relationship data: https://github.com/wvteijlingen/Spine/blob/master/Spine/Resource.swift#L104
Whether your associated User has been included or not.

@gaetanm
Copy link
Author

gaetanm commented Apr 12, 2017

Thanks, it's more clear now.

I have a last error message:

'[<DoEat.Menu 0x6100002e4b80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key nbrOfRecipes.'

No clue about why I have that error. I already had a similar error message in the past but it was caused by the storyboard, which seems to not be the case here.

@markst
Copy link

markst commented Apr 19, 2017

@gaetanm nbrOfRecipes must be a NSNumber. see documentation for using primitive types

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants