when setting up the relation in code, you could try:
var findById = function(id, cb) {
...
};
reverse.shared = true; // remoting
Category.hasMany(Product, { scopeMethods: {
findById: findById
} });
Here's a more elaborate example, which I'm using to allow a model to be found by id or slug:
var relationName = 'products';
var propertyName = 'slug';
var relation = Model.relations[relationName];
var scope = Model.scopes[relationName];
var idName = Model.dataSource.idName(relation.modelTo.modelName);
var wrapMethod = function(methodName) {
return scope.methods[methodName] = (function(method) {
return function() {
var self = this;
var args = _.toArray(arguments);
if (_.isObjectID(args[0])) {
method.apply(self, args);
} else {
var findById = methodName === 'findById';
var cb = _.last(args);
var cond = { where: {}, limit: 1, fields: {} };
cond.fields[propertyName] = true;
cond.fields[relation.keyTo] = true;
cond.fields[idName] = true;
if (findById) delete cond.fields; // ignore
var id = cond.where[propertyName] = args.shift();
this[relationName](cond, function(err, items) {
var item = items[0] || null;
if (findById) return cb(err, item);
if (item) id = item[idName];
method.apply(self, [id].concat(args));
});
}
};
}(scope.methods[methodName]));
};
Model.prototype['__findById__' + relationName] = wrapMethod('findById');
Model.prototype['__updateById__' + relationName] = wrapMethod('updateById');
Model.prototype['__destroyById__' + relationName] = wrapMethod('destroy');
Model.prototype['__exists__' + relationName] = wrapMethod('exists');
But how can i change remote parameters like accepts, returns and similar?
Have you tried the following?
Model.prototype['__findById__' + relationName].accepts = { ... };
Model.prototype['__findById__' + relationName].returns = { ... };
I tried this:
Exercise.prototype.__create__resources = function (req, res, cb) {
var self = this;
self.resources.create({id: new ObjectID()}, function(err, resource) {
if (err) cb(err);
resource.upload(req, res, function(e, d) { self.save(); cb(e, d); });
});
};
Exercise.prototype.__create__resources.accepts = [
{arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}}
];
Exercise.prototype.__create__resources.returns =
{arg: 'resp', type: loopback.getModel("resource"), root: true};
Exercise.prototype.__create__resources.description =
"Uploads exercise resource";
I can override function this way, but no accepts and returns. Any other idea?
Well i found a way, if i also define shared and http properties, it works, but now i have two entries in loopback explorer, so this is just an ugly hack.
UPDATE: This only works sometimes, so don't use it.
@offlinehacker since you are assigning a completely new method, you have to set it to shared, so that's correct. Can you elaborate on the 'sometimes' part?
I will investigate this and see if I can provide a helper function to do this consistently.
OK, looks like strong-remoting allows registering functions by name, and then resolves (a.k.a. binds) them for remoting later. Internally, this list is kept as an array, so that might explain why you're seeing the double entries in explorer.
I would suggest the following for now - can you try this?:
var sharedMethod = Exercise.sharedClass.find('__create__resources', false); // false: non-static
sharedMethod.accepts = [ … ];
sharedMethod.returns = { … };
Exercise.prototype.__create__resources = function (req, res, cb) {
...
};
// Perhaps this is needed:
Exercise.setup();
Hello @offlinehacker
Is this issue still relevant or it is been resolved?
@fabien Thanks a lot for the clarification.
Closing due to inactivity. If you are still running into problems, feel free to leave a comment and I will reopen the issue.
I do need to override User delete method, instead of deleting I want to update "deleted" field. And I want to keep the same path : DELETE /api/User
How can i achieve this in 2016 :) ?
@amaurybrisou Got the same question here !
+1 ..trying to override /api/user/{id}/items
+1 I need to override a hasAndBelongsToMany relation method, /api/entity/{id}/relation/rel/{fk}... overriding the __link__relation function does not work, and I don't quite understand the above suggestions. Is there any documentation about this?
Re-opening issue. ..
+1
+1
Tried to register a remote method on the url of the relation method and it still calls the relation method.
Tried to register it after the "attached" event was fired.
Tried to override the method on the model itself (__create__relation)
Nothing seems to work. Wtf :+1: :)
+1
My work around:
@dktan if you disable remote method /api/user/{id}/items, create your own. How did you define remote method to use the same url pattern? (I mean show "api/user/{id}/items" in explorer and get the "id" in code). I search how to implement in docs, but with no luck.
@windyinwind I did not try with User model, but with my current models, make sure your method signature is:
MyModel.prototype.customMethod = function (filter, cb) {
var self = this;
// You can get id by accessing self.id
...
}
With the "prototype" method declaration, you could have an instance matching with the "id" via self that the loopback-explorer exposes.
@nghiaht @kennethlynne @windyinwind @dktan @loay @superkhau , I am able to override the inbuilt remote methods of the relation as following:
const app = require('../../');
module.exports = function(Customer) {
app.on('started', function() {
const originalFindOrders = Customer.prototype['__findById__orders'];
Customer.prototype['__findById__orders'] = function() {
//custom logic here
originalFindOrders.apply(this, arguments);
};
});
};
@superkhau @bajtos , it would be helpful to add documentation on overriding inbuilt remote methods. I will do it this sprint.
Connect to #443
Actually, closing in favour of #443
Hi. I have some situation here. I'd like the existence of the "documented" parameter to bypass swagger without lose the remoting functionalities. Well, I realised that I can run a boot script, selecting which endpoint deploy on swagger and which not, but, the issue is with related models, I cannot apply the documented property. I think is related with this issue, I'd like to override the by default "documented" attribute set as shared method. Is there a way to do that with related models?
Thanks!
Most helpful comment
Tried to register a remote method on the url of the relation method and it still calls the relation method.
Tried to register it after the "attached" event was fired.
Tried to override the method on the model itself (__create__relation)
Nothing seems to work. Wtf :+1: :)