Rails アプリ データベースの資格情報を使用して、Titanium アプリにログインできるようにしたいと考えています。
Titanium で、次のモデルを作成しました。
exports.definition = {
config: {
'adapter': {
'type': 'myAdapter',
'base_url': 'http://server:3000/api/users/'
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// custom functions
login: function() {
this.sync("login", this);
}
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {});
return Collection;
}
}
Appcelerator の公式ドキュメントにある Twitter の例から、私が作成した同期アダプター:
// Global URL variable
var BASE_URL = 'http://server:3000/api/';
// Override the Backbone.sync method with the following
module.exports.sync = function(method, model, options) {
var payload = model.toJSON();
var error;
switch(method) {
// custom cases
case 'login':
http_request('POST', BASE_URL + 'login', payload, callback);
break;
// This case is called by the Model.fetch and Collection.fetch methods to retrieve data.
case 'read':
// Use the idAttribute property in case the model ID is set to something else besides 'id'
if (payload[model.idAttribute]) {
// If we have an ID, fetch only one tweet
http_request('GET', BASE_URL + '', {
id : payload[model.idAttribute]
}, callback);
} else {
// if not, fetch as many as twitter will allow us
http_request('GET', BASE_URL + '', null, callback);
}
break;
// This case is called by the Model.save and Collection.create methods
// to a initialize model if the IDs are not set.
// For example, Model.save({text: 'Hola, Mundo'})
// or Collection.create({text: 'Hola, Mundo'}) executes this code.
case 'create':
if (payload.text) {
http_request('POST', BASE_URL + 'update.json', {
status : payload.text
}, callback);
} else {
error = 'ERROR: Cannot create tweet without a status!';
}
break;
// This case is called by the Model.destroy method to delete the model from storage.
case 'delete':
if (payload[model.idAttribute]) {
// Twitter uses a POST method to remove a tweet rather than the DELETE method.
http_request('POST', BASE_URL + 'destroy/' + payload[model.idAttribute] + '.json', null, callback);
} else {
error = 'ERROR: Model does not have an ID!';
}
break;
// This case is called by the Model.save and Collection.create methods
// to update a model if they have IDs set.
case 'update':
// Twitter does not have a call to change a tweet.
error = 'ERROR: Update method is not implemented!';
break;
default :
error = 'ERROR: Sync method not recognized!';
};
if (error) {
options.error(model, error, options);
Ti.API.error(error);
model.trigger('error');
}
// Simple default callback function for HTTP request operations.
function callback(success, response, error) {
res = JSON.parse(response);
console.log("response |" + response);
console.log("res |" + res);
console.log("res str |" + JSON.stringify(res))
console.log("options |" + options);
if (success) {
// Calls the default Backbone success callback
// and invokes a custom callback if options.success was defined.
options.success(res, JSON.stringify(res), options);
}
else {
// res.errors is an object returned by the Twitter server
var err = res.errors[0].message || error;
Ti.API.error('ERROR: ' + err);
// Calls the default Backbone error callback
// and invokes a custom callback if options.error was defined.
options.error(model, err, options);
model.trigger('error');
}
};
};
// Helper function for creating an HTTP request
function http_request(method, url, payload, callback) {
// Generates the OAuth header - code not included
var header;
//= generate_header(method, url, payload);
var client = Ti.Network.createHTTPClient({
onload : function(e) {
if (callback)
callback(true, this.responseText, null);
},
onerror : function(e) {
if (callback)
callback(false, this.responseText, e.error);
},
timeout : 5000
});
// Payload data needs to be included for the OAuth header generation,
// but for GET methods, the payload data is sent as a query string
// and needs to be appended to the base URL
if (method == 'GET' && payload) {
var values = [];
for (var key in payload) {
values.push(key + '=' + payload[key]);
}
url = url + '?' + values.join('&');
payload = null;
}
client.open(method, url);
//client.setRequestHeader('Authorization', header);
client.send(payload);
};
// Perform some actions before creating the Model class
module.exports.beforeModelCreate = function(config, name) {
config = config || {};
// If there is a base_url defined in the model file, use it
if (config.adapter.base_url) {
BASE_URL = config.adapter.base_url;
}
return config;
};
// Perform some actions after creating the Model class
module.exports.afterModelCreate = function(Model, name) {
// Nothing to do
};
Rails アプリは JSON で応答し、動作しますが、問題はコールバック関数にあります。
[INFO] : response |{"email":"huhu@gmail.com","password":null}
[ERROR] : Script Error {
[INFO] : res |[object Object]
[INFO] : res str |{"email":"huhu@gmail.com","password":null}
[INFO] : options |[object Object]
[ERROR] : backtrace = "#0 () at file://localhost/.../xxx.app/alloy/sync/myAdapter.js:4";
[ERROR] : line = 30;
[ERROR] : message = "'undefined' is not a function (evaluating 'options.success(res, JSON.stringify(res), options)')";
[ERROR] : name = TypeError;
[ERROR] : sourceId = 216868480;
[ERROR] : sourceURL = "file://localhost/.../xxx.app/alloy/sync/myAdapter.js";
[ERROR] : }
それで、誰かがオプションが未定義である理由を知っていますか...? read メソッドを使用してユーザーを取得するために fetch メソッドを呼び出すと、機能することに注意してください。ところで、誰かを認証する良い方法はありますか?