Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to override the url in has_many relation #59

Closed
bunzli opened this issue Jul 19, 2014 · 17 comments
Closed

how to override the url in has_many relation #59

bunzli opened this issue Jul 19, 2014 · 17 comments
Assignees
Milestone

Comments

@bunzli
Copy link
Member

bunzli commented Jul 19, 2014

I would like that my

parts: { hasMany: 'BikePart' }

request to bikes/3/bike_parts instead of bikes/3/parts

@blackjid
Copy link
Member

I think you could do something like this

parts: { hasMany: 'BikePart', path: 'parts'}

@bunzli
Copy link
Member Author

bunzli commented Jul 19, 2014

awesome! thank's @blackjid

@bunzli
Copy link
Member Author

bunzli commented Jul 20, 2014

I don't know if i'm doing something wrong or there's a little bug here.

The attribute path works fine when the data from the api doesn't came with parts

{
    name: 'copito',
    parts: [
        {
             id: 1,
             ...
        }
    ],
    ...
}

But when parts is present in the response, it seems to be loaded as a plain array, so i'm not able to create new parts.

@iobaixas
Copy link
Member

If you set path: 'bike_parts, then restmod will also expect inline data to come at the bike_parts attribute.

To tell restmod to use 'parts' as the attribute name you can use the source modifier, like this:

parts: { hasMany: 'BikePart', path: 'bike_parts', source: 'parts' }

@iobaixas
Copy link
Member

After digging a little more I found out that actually if you use path: 'bike_parts' you will also need source: 'bikeParts' added because the transformation function expects camelcase names for decoders by default.

This should be fixed in a way that using path: 'bike_parts' registers the properly cased decoder (depending on the configured nameEncoder).

@iobaixas iobaixas added the bug label Jul 21, 2014
@iobaixas iobaixas added this to the 1.0 milestone Jul 21, 2014
@bunzli
Copy link
Member Author

bunzli commented Jul 21, 2014

Yeah!, thank's a lot @iobaixas

@bunzli bunzli closed this as completed Jul 21, 2014
@iobaixas
Copy link
Member

Don't close it just yet, I need to check the naming thing first.

@iobaixas iobaixas reopened this Jul 21, 2014
@bunzli
Copy link
Member Author

bunzli commented Jul 21, 2014

sorry

@smajl
Copy link

smajl commented Oct 16, 2015

@iobaixas @bunzli: Guys, please, can you help me? I have huge problems getting to work this simple response with pre-inlined resource:

{
  id: 1,
  productTags: {
    data: [...], // we use {data: [], metadata: {}} structure for collections
    metadata: {...}
  },
  ...
}

My model definition:

...
  return restmod.model('/products').mix({
    productTags: {
      hasMany: 'Tag', mask: 'CU', path: 'tags', source: 'productTags.data'
      // also tried: hasMany: 'Tag', mask: 'CU', path: 'tags', map: 'productTags.data'
    },
...

After fetching /products the productTags object gets restmodized to array with restmod functions attached. So far good. But whenever I save the the parent product resource I get Collection $decode expected array error and the productTags array gets emptied.

Does it only work with structures like:

{ id: 1, inlinedCollection: [...], ... }

or I am missing something else here? Help really appreciated.

Important note: I want to read and init from pre-inlined data, but creating and updating is performed on separate routes like /products/1/tags and I want to use the same object/array for all these operations.

@iobaixas
Copy link
Member

Hi @smajl, this is probable because restmod expects create/update (POST/PUT) requests to respond with a structure similar to show (GET). Could you share with us some sample output from the create request triggered when a new tag is created?

@smajl
Copy link

smajl commented Oct 20, 2015

@iobaixas I am not trying to save tag here, but the product. And I am masking out all the inlined collections (productTags included) in create/update requests - as I said, I need to use separate routes to do these operations (like POST product/1/tags {...}). I don't understand where you are heading with this. Can't be a problem in a packer or something?

@iobaixas
Copy link
Member

The packer only works on the root of the request, not on each object that get decoded, so I don't think there is a problem there.

From the error you pasted before (Collection $decode expected array), I'm assuming there is a problem when decoding the response from the POST request. The problem I think you are experiencing is due to the response from the POST containing some kind of object that gets decoded into the product and messing things up. Masking a property from create/update only prevents it from being sent.

I insist on you sharing the POST response, the problem is probably related to that.

@smajl
Copy link

smajl commented Oct 21, 2015

@iobaixas To be specific, I am updating, so it's PUT request and response is empty, our backend implementation is not sending any responses on PUT requests - sorry, I can't paste anything. The error is fired after after-request hook.

The stacktrace is:

Error: Collection $decode expected array
    at Object.Utils.assert (angular-restmod-bundle.js:4016)
    at Array.$decode (angular-restmod-bundle.js:495)
    at Array.$decode (angular-restmod-bundle.js:1153)
    at Array.$decode (angular-restmod-bundle.js:4086)
    at Model.<anonymous> (angular-restmod-bundle.js:2441)
    at decodeProp (angular-restmod-bundle.js:3594)
    at decode (angular-restmod-bundle.js:3556)
    at Function.decode (angular-restmod-bundle.js:3679)
    at Model.$decode (angular-restmod-bundle.js:1471)
    at Model.$decode (angular-restmod-bundle.js:1153)

The problem is that the $decode function in RMExtendedApi module (line 1151) is fed with empty _raw and I don't why and how to prevent it. :( Your help is really appreciated.

@iobaixas
Copy link
Member

Could you try this:

In your base model add the following hook:

hooks: {
  'after-request': function(_req) {
    if(!_req.data) _req.data = {};
  }
}

@smajl
Copy link

smajl commented Oct 21, 2015

Wow, thank you thousand times, seems like that did the trick!!!

Final model looks like this:

  return restmod.model('/products').mix({
    // I don't even need to mask this, it does not get send on updates
    productTags: { hasMany: 'Tag', source: 'productTags.data' },
    ...
    '$hooks': {
      'after-request': function (_req) {
        if(!_req.data) _req.data = {};
      }
    }
  });

Awesome, thanks again, but this was a bit tricky. Is this normal behavior or is our JSON data from server or defined model somehow special?

@iobaixas
Copy link
Member

@smajl, it was a somewhat difficult to spot bug in the serialization module.

Thanks for your feedback!

@iobaixas
Copy link
Member

@smajl, I'm not sure if the REST standard recommends that POST/PUT requests must return some content. At least in APIs made by us we always return the created/updated object in the response.

iobaixas added a commit that referenced this issue Oct 24, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants