Skip to content

Instantly share code, notes, and snippets.

@wagenet
Created May 13, 2010 19:41
Show Gist options
  • Save wagenet/400350 to your computer and use it in GitHub Desktop.
Save wagenet/400350 to your computer and use it in GitHub Desktop.
SproutCore Rails DataSource
MyApp.MyModel.mixin({
resourcePathFor: function(action, storeKey, item) {
var id, path;
id = storeKey ? MyApp.store.idFor(storeKey) : null;
switch(action) {
case 'fetch':
case 'create':
path = 'items';
break;
case 'retrieve':
case 'update':
case 'destroy':
path = 'items/'+id;
}
return path;
},
resourceBaseParam: 'item',
resourceParamsFor: function(action) {
var params = "attr1 attr2".w();
if (action == 'create') params.push('guid');
return params;
}
});
/** @class TODO: Describe Class
@extends SC.DataSource
@since SproutCore 1.0
*/
// For testing
SC.DISABLE_REMOTE_REQUESTS = NO;
SC.RailsDataSource = SC.DataSource.extend( {
_resourcePathFormat: '/sc/%@.json%@',
getFullResourcePath: function(resourcePath, queryParams) {
var params = '';
if (queryParams) {
var i = 0;
for (var key in queryParams) {
if (queryParams.hasOwnProperty(key)) {
params += '%@%@=%@'.fmt(i === 0 ? '?' : '&', key, queryParams[key]);
i++;
}
}
}
return this._resourcePathFormat.fmt(resourcePath, params);
},
// STANDARD DATA SOURCE METHODS //
fetch: function(store, query) {
var recordType = query.recordType || query.recordTypes[0];
var url = this.getFullResourcePath(recordType.resourcePathFor('fetch'));
var fetchParams = { query: query, store: store };
if (!SC.DISABLE_REMOTE_REQUESTS) {
return NO;
} else {
SC.Request.getUrl(url).set('isJSON', YES)
.notify(this, this._didFetchRecords, fetchParams)
.send();
return YES; // Not necessary, but good form
}
},
retrieveRecord: function(store, storeKey, id) {
// map storeKey back to record type
var recordType = SC.Store.recordTypeFor(storeKey);
var url = this.getFullResourcePath(recordType.resourcePathFor('retrieve', storeKey));
var retrieveParams = { store: store, storeKey: storeKey };
if (SC.DISABLE_REMOTE_REQUESTS) {
return NO;
} else {
SC.Request.getUrl(url).set('isJSON', YES)
.notify(this, this._didRetrieveRecord, retrieveParams)
.send();
return YES;
}
},
createRecord: function(store, storeKey, params) {
var dataHash = store.readDataHash(storeKey),
recordType = SC.Store.recordTypeFor(storeKey),
obj = this._dataToParams(recordType, 'create', dataHash);
var url = this.getFullResourcePath(recordType.resourcePathFor('create', storeKey, dataHash));
var createParams = { store: store, storeKey: storeKey };
if (SC.DISABLE_REMOTE_REQUESTS) {
this._didCreateRecord(null, createParams);
} else {
SC.Request.postUrl(url).set('isJSON', YES)
.header('X-Requested-With', 'XMLHttpRequest')
.notify(this, this._didCreateRecord, createParams)
.send(obj);
}
return YES ;
},
updateRecord: function(store, storeKey, params) {
if(!params) params = {};
var id = store.idFor(storeKey),
dataHash = store.readDataHash(storeKey),
recordType = SC.Store.recordTypeFor(storeKey),
obj = this._dataToParams(recordType, 'update', dataHash),
request;
var url = this.getFullResourcePath(recordType.resourcePathFor('update', storeKey));
var updateParams = { store: store, storeKey: storeKey };
if (!SC.DISABLE_REMOTE_REQUESTS) {
// Send request unless disabled
request = SC.Request.putUrl(url).set('isJSON', YES).header('X-Requested-With', 'XMLHttpRequest');
// Don't notify if skipping response
if (!params.skipResponse) request.notify(this, this._didUpdateRecord, updateParams);
request.send(obj);
}
if (SC.DISABLE_REMOTE_REQUESTS || params.skipResponse) {
// Don't wait for a server response
this._didUpdateRecord(null, updateParams);
}
return YES ;
},
destroyRecord: function(store, storeKey, params) {
if (!params) params = {};
var status = store.readStatus(storeKey);
if (status === SC.Record.DESTROYED_CLEAN) {
// Already clean - probably from calling destroy on a new record
// Is there a better place to handle this?
store.removeDataHash(storeKey, status);
store.dataHashDidChange(storeKey);
} else {
// Destroy normally
var id = store.idFor(storeKey),
recordType = SC.Store.recordTypeFor(storeKey),
notifyParams = { store: store, storeKey: storeKey };
var url = this.getFullResourcePath(recordType.resourcePathFor('destroy', storeKey));
if (params.noRequest || SC.DISABLE_REMOTE_REQUESTS) {
this._didDestroyRecord(null, notifyParams);
} else {
SC.Request.deleteUrl(url)
.header('X-Requested-With', 'XMLHttpRequest')
.notify(this, this._didDestroyRecord, notifyParams).send();
}
}
return YES ;
},
cancel: function(store, storeKeys) {
return NO;
},
_didFetchRecords: function(response, params) {
var store = params.store,
query = params.query,
results = response.get('response'),
resultItem, cleanedResults= [], obj;
if (SC.$ok(response)) {
for(idx=0; idx < results.length; idx++) {
resultItem = results[idx];
// Hackish way to ignore key
for (var k in resultItem) {
obj = resultItem[k]; break;
}
cleanedResults.push(obj);
}
// load the contacts into the store...
store.loadRecords(params.recordTypes, cleanedResults);
// notify store that we handled the fetch
store.dataSourceDidFetchQuery(query);
} else {
// handle error case
store.dataSourceDidErrorQuery(query, response);
}
},
_didRetrieveRecord: function(response, params) {
var store = params.store,
storeKey = params.storeKey,
results = response.get('response'),
cleanedResults;
if (SC.$ok(response)) {
// normal: load into store...response == dataHash
// Get first item
for (var k in results) {
cleanedResults = results[k]; break;
}
store.dataSourceDidComplete(storeKey, cleanedResults, cleanedResults.id);
} else {
// error: indicate as such...response == error
this._processError(storeKey, response);
}
},
_didCreateRecord: function(response, params) {
var results = response && response.get('response'),
storeKey = params.storeKey,
store = params.store,
resultsKeys= [], cleanedResults;
if (!response) {
// Request was skipped, pretend it succeeded
store.dataSourceDidComplete(storeKey);
} else if (SC.$ok(response)) {
for(var k in results) resultsKeys.push(k);
cleanedResults = results[resultsKeys[0]];
store.dataSourceDidComplete(storeKey, cleanedResults, cleanedResults.id);
} else this._processError(storeKey, response);
},
_didUpdateRecord: function(response, params){
var storeKey = params.storeKey,
store = params.store;
if (SC.$ok(response)) {
store.dataSourceDidComplete(storeKey);
} else this._processError(storeKey, response);
},
_didDestroyRecord: function(response, params){
var storeKey = params.storeKey,
store = params.store;
// Response will be null if no actual request made and SC.$ok will still evaluate true
// This is fine since we want to pretend we succeeded anyway
if (SC.$ok(response)) {
store.dataSourceDidDestroy(storeKey);
} else this._processError(storeKey, response);
},
_processError: function(storeKey, response) {
var status = response.get('status');
if (status === 401) { // Unauthorized
SC.AlertPane.error("Not signed in", "You are not signed in. Please sign in again.");
}
store.dataSourceDidError(storeKey, response);
},
_dataToParams: function(recordType, action, data) {
var resourceParams = recordType.resourceParamsFor(action),
baseParam = recordType.resourceBaseParam,
cleanedData = {}, item;
cleanedData[baseParam] = {};
for (v in data) {
item = data[v];
if(resourceParams.indexOf(v) != -1 && item != null) {
if(item == true) item = 1;
if(item == false) item = 0;
cleanedData[baseParam][v] = item;
}
}
return cleanedData;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment