In my sails.js application i have two routes like this:
'/': {controller:'HomeController',action:'home'},
'GET /:category/:subcategory/:keyword':{controller:'SearchController',action:'index'
When I run the default route (/) it will always execute this route
GET /:category/:subcategory/:keyword .
Why is this happening??
The order of routes in route file is
1) /
2) GET /:category/:subcategory/:keyword
As mentioned in the comment above, your very general route /:category/:subcategory/:keyword is being hit because it must match asset urls on your homepage. This route will match any three-part path, ex:
/images/icons/smiley.png
/scripts/thirdparty/jquery.min.js
Etc!
There would be two approaches to fix this. One would be making your SearchController urls more specific. Maybe /search/:category/:subcategory/:keyword would be a good idea? This is the simplest and should clear up any conflicts with your assets right away.
But if you really need catch-all routes that can interfere with other specific routes, then the solution is to catch the specific routes first. For example, in routes.js:
'GET /images/*': 'RouteController.showAsset',
'GET /scripts/*': 'RouteController.showAsset',
'GET /styles/*': 'RouteController.showAsset',
//...
'GET /:category/:subcategory/:keyword': 'SearchController.index',
Then create a controller RouteController with the method:
showAsset: function(req, res) {
var pathToAsset = require('path').resolve('.tmp/public', req.path);
// ex should be '.tmp/public/images/icons/smiley.png'
return res.sendfile(pathToAsset);
},
You may need to add something in to check for file existence first, but this is the idea.
I found this approach worthwhile when I wanted a /:userName route that would not conflict with all of my /contact, /about, /robots.txt, /favicon.ico, etc. However, it takes work to maintain, so if you think the first approach can work for you, I would use that.
Related
I've got some troubles when start working with Next.js
Here is the deal. I have multiple filters, depends on them I make up URL. All of this URL's for one page.
It can be like:
/
/one
/one/two
/one/two/three
This nested is required. How can I create one handler for catch any of these URL's?
I use Express like this, but it doesn't help.
server.get('/*', async (req, res, next) => {
try {
app.render(req, res, '/')
} catch (e) {
next(e)
}
})
Thanks!
Use Dynamic routing like that :
pages/[one]/[two]/[three].js
cf:
Multiple dynamic route segments work the same way.
For example, pages/post/[pid]/[comment].js would match /post/1/a-comment. Its query object would be: { pid: '1', comment: 'a-comment' }.
https://nextjs.org/docs#dynamic-routing
Hope it's help.
New feature introduced in Next.js 9.5
Solution: Rewrites
See also: Redirects & Headers:
Announcing comment: https://github.com/vercel/next.js/discussions/9081#discussioncomment-48301
Besides that I am aware of some wildcard matching that nests paths deep in the default routing, but I feel Rewrites is a better solution in most use cases.
use npm next-routes in order to use path patterns (regex) to bind multiple urls to a page
I have a case using Ember where I want to make the top level URL available (ie. localhost:4200/demo), and have all the routes underneath also display the same URL (localhost:4200/demo). So the route file, if possible would look something like:
this.route('demo', function() {
this.route('one', { path: '/' });
this.route('submit', { path: '/' });
});
I understand that ENV.locationtype can be set for the whole app, but is there a way to conditionally set this for specific URLs underneath a parent URL?
Generally when you end up hitting major snags like this it is because Ember is implicitly trying to tell you that what you are doing isn't a good idea.
Is there a particular reason that you don't want your sub-routes to affect the URL in any way? Could you get by with random values in the URL if your prime purpose is to obfuscate things?
Ember uses the URL to work out what state things should be in in your app. If you don't want to use the routes at all you wouldn't have to, but then at that point you are dealing with a nested hierarchy of components that you have to switch between yourself. Which would in essence be akin to using React without a router ...
By default, Ember can manage URLs, or it can be set to not manage them, but it seems like the desired intent is to have it do both in a single environment, which is not logically allowed.
If none is declared for ENV.locationtype, then Ember's default URL management is turned off. This is an "environment-wide" configuration.
If the Ember Router is being used to map nested routes, and default URL management is in play, then observe that you cannot have the same URL path defined for multiple, sibling, child routes.
A further observation, is that your attempt above is tapping into functionality governed by the single index route that is available at every nesting level within the Router map. However, a route cannot have multiple index routes. Only the last one defined will be recognized.
Router.map(function() {
this.route('demo', function() {
this.route('one', { path: '/' }) // <-- this is over-ridden by "submit"
this.route('submit', { path: '/' }) // <-- this defines an "index" route for demo
})
})
I am about to redo code switching from Angular 1 to React. I have been using React Boilerplate for a while, which uses React Router v3, and I really like the setup. My Angular project uses URLs like example.com/#/about and I really don't like the concept of the # sign so I want to make the URL look like example.com/about.
The problem is some URLs have been given out to the public so I would like for them to be backward-compatible. For example, if a user goes to /#/about, then they will be automatically redirected to /about.
If you know the React Boilerplate's ecosystem, that would be helpful. I know the concept of redirecting is simple, but I would like to do this in a clean way within the boilerplate. Any ideas?
Thanks!
Thanks to #Calvin's comment above, it sent me down a different thought process. I found out that React Boilerplate allows redirects like so:
onEnter: (_nextState, replace, next) {
replace('/something');
next();
}
This is to be placed inside of the routes.js file. The link to the question/answer where I found this answer is here.
Edit
The exact answer ended up being this function:
const sniffHash = (nextState, replace, next) => {
if (nextState.location.hash !== '') {
let path = nextState.location.hash.replace('#', '');
replace(path);
}
next();
}
in which I used the variable name on my home route like so:
path: '/',
name: 'home',
onEnter: sniffHash,
getComponent(nextState, cb) {
//React Boilerplate router stuff
}
The only caveat is if I needed anchor links, then I would have to figure something out. Not ideal, but it may help someone who has to make this type of transition.
Currently I have two routes in my app:
/invoice/:invoice returns JSON data of an Invoice document from Mongoose
/invoice/preview returns a preview of an invoice inside an HTML template (note that this doesn't always preview an existing invoice, it could also be a non-existing of which its data is supplied via url parameters, which is why the route cannot be /invoice/:invoice/preview)
Question
There should be a better way to declare these two specific routes, because the /invoice/preview route now calls both handlers, since it matches both regexes.
If we were talking in CSS selectors /invoice/:invoice:not(preview) would be the behavior I want. Unfortunately I don't find any documentation for this.
Is there any way to achieve this or any way to improve this endpoint structure?
Declare more specific routes first:
router.get('/invoice/preview', ...);
router.get('/invoice/:invoice', ...);
Express checks routes in order of declaration, so once it has matched a request against /invoice/preview (and provided that its handler sends back a response), the less-specific /invoice/:invoice won't be considered.
Alternatively, if :invoice should always match a specific pattern (say a MongoDB ObjectId), you can limit the route to requests matching that pattern:
router.get('/invoice/:invoice([a-fA-F0-9]{24})', ...);
That pattern doesn't match "preview", so the order wouldn't matter so much in that case.
If this isn't possible, you could create a middleware that would check if req.params.invoice matches "preview" and, if so, would pass along the request further down the handler chain:
let notIfPreview = (req, res, next) => {
if (req.params.invoice === 'preview') return next('route');
next();
};
router.get('/invoice/:invoice', notIfPreview, ...);
router.get('/invoice/preview', ...);
(documented here)
In Ember I can use this:
App.Router.map(function() {
this.route('accomodations');
});
so if one goes to /accomodations it will load that view.
I can also add:
App.Router.map(function() {
this.route('accomodations', { path: '/travel' });
});
so if one goes to /travel, it will go to the same view.
I want to be able to have /accomodations and /travel go to the same view? is this possible?
I know that this:
App.Router.map(function() {
this.route('accomodations');
this.route('accomodations', { path: '/travel' });
});
Will do what I'm asking, but if they go to accommodations, it should show that in the url, it always shows travel. I'm not even sure if the final piece of code is best practice.
You can simply interchange the two route-path definition lines:
App.Router.map(function() {
this.route('accomodations', { path: '/travel' });
this.route('accomodations');
});
The last definition takes the precedence for URL display in {{link-to ...'accomodations'}} and Route#transitionTo('accomodations') in-app transitions, though entering the app by '/travel' will leave the URL as is.
(EmberJS 1.11.3, 2.12.2)
Using redirection
In router.js
App.Router.map(function() {
this.route('accomodations');
this.route('travel');
});
In routes/travel.js
App.TravelRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('accomodations');
},
});
You do not have to put these in separate files (that's just where I would put them).
What this does is register two routes with the router. Pick one of them to be the "main" route, and the other the "alias" route. In this case, accomodation is the main route, and travel is its alias. When the user visits /travel, they get redirected to /accomodation.
This would be the default/ standard Ember way of accomplishing this, and if this sounds good to you, go for this.
Another possible solution
If you do not wish to have redirection happen, for some reason, and want the URL seen by the user to stay the same, but still display the same things, and behave in the same way, this is also possible.
In this case, you would create two of every single Ember unit (route, controller, view, template). The smart way would be to create a base class route, and have both App.TravelRoute and App.AccomodationRoute trivially extend it; create a base class controller, and have both App.TravelController and App.AccomodationController trivially extend it; same for views, if you have them.
Templates, OTOH, are a little trickier, because there is not way to extend them (that I know of). SO what you would need to do, is create either a partial or a component (decided which works better for you), and then reuse that partial/ component in both templates/accomodation.hbs and templates/travel.hbs