14

我正在访问一个 REST 服务,它公开了这两个资源,一个父资源和一个子资源:

/users
/users/{userId}/account

所以资源“帐户”没有嵌套在资源“用户”中,它必须被第二个请求访问。有此类 REST API 的示例,例如这里

我使用这些模型将用户及其帐户映射到 Ext Js 4 数据模型:

用户

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"
        }
    }
});

帐户

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

帐户代理没有 url(我希望这将基于父用户模型创建)。当我调用 user.getAccount() 时,我得到一个异常,因为代理缺少 url。

问题是否有某种方法可以设置模型,以便 Ext Js 访问 /users/{userId}/account 而无需使用每个父 userId 手动更新帐户代理 url?

4

2 回答 2

26

你不会从股票 Ext 类中得到你想要的东西,你将不得不变得有点肮脏......

据我了解,您需要用户的 id 来加载其帐户,而不是帐户记录本身的 id。因此,我将配置关联以反映这一点:

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

这里最大的优势是当它被要求为请求构建 url 时,用户 ID 将可供代理使用。

现在,为了以您需要的格式构建 url,我们必须替换代理的buildUrl方法。而且,正如您已经发现的那样,您首先需要一个 url 才能访问此方法。

所以,这里是我将如何配置帐户代理:

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);
    }
}

在这一点上,我们最终在表单的 url 上发出代理触发请求:

rest/users/45/account?id=45

这只是装饰性的,但那个 id 查询参数让我很烦,所以我也将buildRequest代理的方法替换为以下方法:

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;
}

而且,你在这里......虽然它会起作用,但我真的不建议在代理的配置中以这种方式覆盖方法。在现实生活中,您应该从 Rest 扩展您自己的代理类,特别是如果您需要配置许多这样的代理……但我希望我已经为您提供了入门所需的所有要素!

于 2013-07-25T12:17:04.347 回答
5

我遇到了同样的问题,我发现 rixo 的回答绝对令人惊叹。因此我自己采用了它,但后来我做了一些修改,所以这是我目前正在使用的代码。优点是它允许您完全按照自己的喜好设置服务 URL 的格式,甚至可以连接多个参数。

// 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);
                }

这样你就可以使用像“ /service/{param1}/{param2}/?abc={param3} ”这样的url,给定一个“request.params”对象

{ “param1”:“value1”,“param2”:“value2”,“param3”:“value3”}

并且也没有必要重写“buildRequest”方法,因为这里使用的任何参数都从“params”对象中删除,并且以后不会连接到查询字符串。

我希望这会有所帮助,欢迎任何评论!

于 2015-08-28T12:11:11.877 回答