I'm using SailJS to build a REST API.
I've a lot of nested models, such as:
A building has many Floors, which have many Apartments, which have an Owner.
The Sails populate implementation doesn't work as expected, and I can populate at max a single level nested model.
In order to make things work I would like to rewrite custom controllers like this:
controllers/BuildingController.js
module.exports = {
find: function (req, res) {
// Custom code with population
}
findOne: function (req, res) {
// Custom code with population
}
create: function (req, res) {
// Custom code with nested object creation and connection to parent object
}
...
}
If I call an endpoint through the blueprint my custom controller for that model is called, but if I call it from another point in the code (e.g. Apartment.find()) Sails use its default action, not mine.
Do you have some kind of hint or solution to this problem? Is this possible to implement?
Thanks in advance
Related
I'm working on an express rest api using sequelize. I successfully generated my models using sequelize-auto (which created init-models.js) and haven't thought about it since. My tables have associations and they show up in the init-models.js file but I can't seem to use query associating to utilize the associations.
Here's the init-models.js that sequelize-auto generated:
function initModels(sequelize) {
...
product.belongsTo(manufacturer, { as: "manufacturer", foreignKey: "manufacturer_id" });
manufacturer.hasMany(product, { as: "products", foreignKey: "manufacturer_id"});
return { product, manufacturer }
}
module.exports = initModels;
module.exports.initModels = initModels;
module.exports.default = initModels
So my question is.. is this module getting loaded when my server starts and initializes everything? If not, could I just move my associations directly to the model init function as suggested in the documentation (I think I'd rather do this)?
You'll get a better idea how to register and initialize models and their associations if you look at my other answer here.
As for shown generated code I suppose it would be better to call initModels inside the entry-point or a special DB module right after you have a Sequelize instance initialized to pass it to the function. And if you import this generated module then by default you will only have access to initModels to be able to call it wherever you wish to initialize models and to get them returned.
Basically, is it possible to write code like this with two middleware functions (authenticateToken and authenticateAdminKey) ?
app.post('/api', authenticateToken, authenticateAdminKey, function() {
...
}
I know something similar is possible when you're using multiple middleware for all the endpoints (as mentioned here). But I wanted to know if something like this is possible for just one endpoint?
middleware list pass in array
app.post('/api', [authenticateToken, authenticateAdminKey], function() {
...
}
I've created some code using a View Composer where I am passing my Route Collection through to the front end on all views, so I can access all of my laravel routes in Vuejs via the route named associated with them.
For example, to upload an image using a vue component, instead of passing my upload route into the Vue Component, it is listed as a part of a global variable:
var uploadRoute = _.find(globalRoutes, function(route) { return route.name == 'route-name.image.upload' });
$.post(uploadRoute, data) ... etc
My question is...is this sensible? I'm publically publishing my entire app's routes.
Thanks
I think your hunch about exposing your entire apps routes is legit. IMO you should explicitly pick out the routes that you need. So in thise case, you should only expose route-name.image.upload. You could create a tiny helper function to look up routes and output them along with the URL as JSON.
function json_routes(array $routes)
{
$return = [];
foreach($routes as $route)
{
$return[$route] = route($route);
}
return new \Illuminate\Support\HtmlString(json_encode($return));
}
And the, in your main view:
var routes = {{ json_routes(["route-name.image.upload"]) }};
Getting a route is simple:
routes['route-name.image.upload'];
This is the most basic exaple I can think of. You can optimize it quite a bit. Just some ideas:
Place the routes in a central place, fx. a config element: json_routes(config('app.json_routes'))
Build a command that generates a static .json file so that you don't iterate through the routes on each page load. Remember to re-generate when you add more routes.
Create a function instead of an object to get the route. That allows you to build in logic and gives a more Laravel-like feel in your js: function route(path){ return window.routes.hasOwnProperty(path) ? window.routes[path] : null ;}
(Advanced) Re-write Laravels router logic and hook into the options array, allowing you to do something like Route::get('dashboard', '...', ['as'=>'dashboard', 'expose'=>true]);, then dynamically generate the before mentioned json-file on all routes with the expose option.
I am using sails-hook-sequelize to load sequelize as the ORM in my sails app. However, my controllers and policies setup (i.e. just creating their methods) is dependent on the models. I need to run the sails-hook-sequelize installable hook before I run controllers and policies hooks (currently it is running it after and the controllers/policies are failing to load). How can I do this? T
Thanks in advance.
Edit: Here is some code to illustrate what I am trying to accomplish:
UserController.js
let Endpoint = require('../classes/Endpoint');
let endpoint = new Endpoint(User);
Object.assign(endpoint, {
find
});
module.exports = endpoint;
function find(req, res, next) {
User.findAll(
{
where: req.query,
include: [
{
model: Privilege,
include: [
{
model: Account,
where: {
accountPkey: {
$in: AuthorizationService.accountsForPrivileges(req.tokenData.privileges, ['ADMINISTRATOR', 'OFFICE MANAGER'])
}
}
}
]
}
]
})
.then(users => res.ok(users))
.catch(err => res.serverError(err));
}
basically, I have a default Endpoint class that I instantiate and then add methods to. You can see that the Endpoint class takes a model argument. However, when this hook runs, the models don't exist yet because they are defined by a third party hook (using sequelize).
There's currently no way to run a third-party hook before the core hooks in Sails.
Often times when I see questions like this, it's from someone who's trying to create a Wordpress-like platform, and they're making the assumption that for every new "entity type" that an end-user creates (i.e. blog, article, comment) they need a new model. An alternative is to create an Entity model, with a contents attribute that is an association to a Content or EntityAttribute model which is more or less just a key/value store. Then you can use wildcard routes to have the EntityController actions load the correct type of entity.
So, I'm using mongojs. To get values into a rendered view, it was my understanding that one had to do something like this:
app.get('/someurl', function(req, res) {
db.mymongocollection.find(function(err, docs) {
//console.log(docs[0].First);
res.render('someview',{first: docs[0].First});
});
});
What if I wanted to move a ton of data to my view? Like the first names and last names for 20 people, but only if they play soccer? I understand that I can change the query parameters (to account for things such as only plating soccer), but is there a way to loop through the docs index somehow?
So I don't have to hardcode something like:
res.render('someview',{first1:docs[0].Name, first2:docs[2].Name .....});
You can just pass the array of documents to your template:
app.get('/someurl', function(req, res) {
db.mymongocollection.find(function(err, docs) {
res.render('someview', { docs : docs });
});
});
And in your template, loop through it:
for doc in docs:
h1 #{doc.First} #{doc.Last}