2013-07-25 15 views
14

sto accede a un servizio REST che espone queste due risorse, una risorsa genitore e una risorsa bambino:Accesso alle risorse REST complessi con Ext JS

/users 
/users/{userId}/account 

Così il "conto" risorsa non è nidificato all'interno della risorsa " utente ", deve essere accessibile da una seconda richiesta. Esistono esempi per tali API REST, ad es. here

io uso questi modelli per mappare gli utenti ei loro account al Ext JS modello di 4 dati:

utente

Ext.define("MyApp.model.User", { 
    extend: "Ext.data.Model", 
    fields: [ { name: "id", type: "string" }], 
    associations: [{ 
      model: "MyApp.model.Account", 
      name: "account", 
      type: "hasOne", 
      reader: "json", 
      getterName: "getAccount", 
      setterName: "setAccount", 
      foreignKey: "accountId" 
     } 
    ], 
    proxy: { 
     type: "rest", 
     url: "/rest/users", 
     reader: { 
      type: "json", 
      totalProperty: "total", 
      root: "users" 
     } 
    } 
}); 

account

Ext.define("MyApp.model.Account", { 
    extend: "Ext.data.Model", 
    fields: [ { name: "id", type: "string" }], 
    belongsTo: "MyApp.model.User", 
    proxy: { 
     type: "rest", 
     reader: { type: "json"} 
    } 
}); 

L'account proxy non ha un URL (speravo che sarebbe stato creato sulla base del tuo genitore modello di ser). Quando chiamo user.getAccount() ottengo un'eccezione perché al proxy manca l'url.

Domanda: C'è qualche modo per configurare i modelli in modo tale che Ext JS accederà/utenti/{} userId/account senza aggiornare manualmente l'account proxy URL con ogni userId genitore?

+0

Il modello di account ha realmente il proprio ID? Ciò non sembra necessario se esiste una relazione uno a uno tra account e utente. – rixo

+0

giusto, l'ID account non è richiesto. – Christoph

risposta

23

non sarà possibile ottenere quello che vuoi dalla classi magazzino Ext, dovrete ottenere un po 'sporca ...

Da quello che ho capito è necessario l'ID dell'utente per caricare il suo conto , non l'ID del record dell'account stesso. Quindi, vorrei configurare l'associazione a riflettere sul fatto che:

associations: [{ 
    model: "MyApp.model.Account", 
    name: "account", 
    type: "hasOne", 
    reader: "json", 
    getterName: "getAccount", 
    setterName: "setAccount", 
    // foreignKey: "accountId" 
    foreignKey: 'id' 
}], 

Il grande vantaggio qui è che l'utente id sarà disponibile per il proxy quando sarà chiesto di costruire l'URL per la richiesta.

Ora, per creare l'url con il formato necessario, è necessario sostituire il metodo buildUrl del proxy. E, come hai già scoperto, hai bisogno di un URL per arrivare a questo metodo in primo luogo.

Quindi, ecco come avrei configurare il proxy Account:

proxy: { 
    type: "rest", 
    reader: {type: "json"}, 

    // Give it an URL to avoid the error 
    url: '/rest/users/{}/account', 

    // Replace the buildUrl method 
    buildUrl: function(request) { 
     var me  = this, 
      operation = request.operation, 
      records = operation.records || [], 
      record = records[0], 
      url  = me.getUrl(request), 
      id  = record ? record.getId() : operation.id; 

     // Here's the part honoring your URL format 
     if (me.isValidId(id)) { 
      url = url.replace('{}', id); 
     } else { 
      throw new Error('A valid id is required'); 
     } 

     // That's enough, but we lose the cache buster param (see bellow) 
     return url; 

     // If we want the cache buster param (_dc=...) to be added, 
     // we must call the superclass, which will read the url from 
     // the request. 
     request.url = url; 
     return Ext.data.proxy.Rest.superclass.buildUrl.apply(this, arguments); 
    } 
} 

A questo punto, si finisce con la richiesta di accensione del proxy su URL del modulo:

rest/users/45/account?id=45 

Questo è solo estetica ma quel parametro di query id mi infastidisce, quindi sostituisco anche il metodo buildRequest del proxy con il seguente:

buildRequest: function(operation, callback, scope) { 
    var me = this, 
     params = operation.params = Ext.apply({}, operation.params, me.extraParams), 
     request; 

    Ext.applyIf(params, me.getParams(operation)); 

    // if (operation.id !== undefined && params[me.idParam] === undefined) { 
    //  params[me.idParam] = operation.id; 
    // } 

    request = new Ext.data.Request({ 
     params : params, 
     action : operation.action, 
     records : operation.records, 
     operation: operation, 
     url  : operation.url, 
     proxy: me 
    }); 

    request.url = me.buildUrl(request); 

    operation.request = request; 

    return request; 
} 

E, eccoti ... Mentre funzionerebbe, in realtà non consiglio di sovrascrivere i metodi in questo modo, nella configurazione del proxy. Nella vita reale, dovresti estendere la tua classe proxy da quella Rest, specialmente se devi configurare molti di questi proxy ... Ma spero di averti dato tutti gli ingredienti necessari per iniziare!

+0

Mi dispiace di poter accettare questa risposta solo una volta :-) La prima frase è la cosa più importante per me, forse dovrei pensare di cambiare il resto delle api. Ho testato la soluzione che hai postato, funziona per me e non ho davvero bisogno di "aggiornare manualmente l'URL del proxy account". Ottimo lavoro! – Christoph

+0

+1 ottima risposta. – Jom

+0

bella risposta! +1 – seba

4

Ho avuto lo stesso problema e ho trovato la risposta di rixo decisamente sorprendente. Quindi l'ho adottato per me stesso, ma poi ho apportato alcune modifiche, quindi questo è il codice che sto usando al momento. Il vantaggio è che ti permette di formattare l'URL del servizio assolutamente come preferisci, concatenando ancora di più quel parametro.

// Replace the buildUrl method 
       buildUrl: function (request) { 
        var me = this, 
         url = me.getUrl(request); 
        var added = []; 
        for(var p in request.params) 
        { 
         if (url.indexOf('{' + p + '}') >= 0) { 
          url = url.replace('{' + p + '}', request.params[p]); 
          added.push(p); 
         } 
        } 
        for(var a in added) 
        { 
         delete request.params[added[a]]; 
        } 

        // That's enough, but we lose the cache buster param (see bellow) 
        return url; 

        // If we want the cache buster param (_dc=...) to be added, 
        // we must call the superclass, which will read the url from 
        // the request. 
        request.url = url; 
        return Ext.data.proxy.Rest.superclass.buildUrl.apply(this, arguments); 
       } 

In questo modo è possibile utilizzare un URL del tipo "/servizio/{param1}/{} param2 /? Abc = {} param3" dato un oggetto "request.params" come

{ "param1": "value1", "param2": "valore2", "param3": "valore3" }

e anche non c'è alcuna necessità di sovrascrivere il "buildRequest" metodo dal momento che qualsiasi parametro utilizzato qui viene rimosso dal oggetto "params" e non è concatenato alla stringa di query in seguito.

Spero che questo aiuti, qualsiasi commento benvenuto!