URL helpers can't recognize additional custom dynamic segments in routes - ruby-on-rails

I am using Rails 4.2. In a gem, there is a route defined as
get 'book/:id', to: 'book#show', as: book
I'd like to add an additional dynamic segment in a custom route, so in the routes.rb file in my app, I have
get ':language/book/:id', to: 'book#show', as: language_book
Then in my controller, I tried to call the url helper
language_book_url language: :en, id: 3
I expect to get a url like http://host:port/en/book/3, however, instead, I get http://host:port/book/3?language=en. It seems I can't use the helper with that extra custom dynamic segment. Is it possible to get the desired path with the new dynamic segment variable? Thanks!
usmanali gave a answer in the comment, to use language_book_url :en, 3. But what if I want a mixture of dynamic segments and query string params? So my target url is http://host:port/en/book/3?barcode=1234. How can I call the url helper? A call to the helper like language_book_url('en', 3, barcode: 1234) would produce http://host:port/book/3?language=en&barcode=1234, instead of the expected one.

Related

How to use URL parameters with router in Vaadin Fusion?

I tried to follow the guide at
Question, which results in a
mobx.esm.js?4fd9:2362 [mobx] Encountered an uncaught exception that was thrown by a reaction or observer component, in: 'Reaction[MainView.update()]' TypeError: Expected "item" to be a string
My configuration is
path: 'item/:item',
component: 'item-view',
Is there an example, how to solve this? Do I need to handle this in the MainView (I follow the todo-tutorial on vaadin.com?
The problem is that main-view.ts in the starter project has logic which tries to list all navigation routes to generate links for them. Currently that logic is not smart enough to detect and skip routes that have non-optional route parameters.
The error is thrown from router.urlForPath(viewRoute.path) when the path has non-optional route parameters because here we are not specifying what the value for the route parameter should be (for the generated URL). For generating a URL for the path 'item/:item' it would need to do something like router.urlForPath('item/:item', { item: 'my-item' }).
The quick fix (to remove the title from the route definition) suggested by Marcus works because the main-view.ts has logic to skip all routes that don't have a title. You could change that logic to also skip by some other criteria or you could try to include values for the route parameters there (for specific routes) if you really want to generate working navigation links for those routes.
Other alternative would be to mark the route parameter as optional (in case you want the route also to be accessible without a parameter) by adding a question mark after it, then the link can be generated without specifying a value for the parameter.
{
path: 'item/:item?', // <- optional route parameter
component: 'item-view',
title: 'Hello World',
}
It seems you have run into an issue with the starter. In main-view.ts, it loops over the routes with a title and tries to create a link for each in the menu:
${this.getMenuRoutes().map(
(viewRoute) => html`
<vaadin-tab>
${viewRoute.title}
</vaadin-tab>
`
)}
However, router.urlForPath() breaks when there is a URL parameter definition instead of an actual parameter (items/:item instead of items/2).
A quick fix for this would be to remove the title property from your route configuration for any route that has a parameter.
{
path: 'item/:item',
component: 'item-view'
// make sure there is no title here
}

Url params encoding

I have a route like this
/api/service/:id
But id is a string like name.of.something
So the the url will look like:
/api/service/name.of.something?other=parameters
The controller can't parse that request correctly because of dots.
How should I decode the id to pass it to the route?
You need to add a constraints option to the route that will cause it to accept periods. Note that this will break Rails' automatic format detection, so you will have to pass an explicit ?format=json to the URL if you specifically need format selection.
get "api/service/:id", to: "some#endpoint", constraints: {id: /[[:alnum:]_\.-]+/i}
Adjust the regex to your preference.

Is there a better way to reference a route by name in a link with AngularDart?

I have many named routes in my AngularDart app. I create links the old fashioned way, like this:
Go
That seems brittle. If I change the path or change the strategy away from hash change, I need to change all my links.
Can I do something like:
<a ng-link="activities">Go</a>
Where activities is the name of the route from my routes config.
For now you can use router to generate those URLs for you.
router.url('activities', {});
The second parameter (should probably be optional) is a map of parameter values. For example, if you have a path like /activity/:activityId then you can do:
router.url('activity', {'activityId', '12345'});
URL generator also honors current state of routes, so lets say you had an active route like foo.bar.baz, and foo was parameterized and you somehow got a hold of bar route (ex. via RouteProvider or queried router.root.getRoute('foo.bar')) then you don't need to know the values of the foo route parameters to generate the URL for baz, you can do:
Route bar = router.root.getRoute('foo.bar');
router.url('baz', {}, startingFrom: bar);
For now you will need to manually insert the generated URL into the template:
link

ASP.NET MVC AnchorLink not using route values?

I'm using AnchorLink on a very simple site with just two routes defined, one standard route and another area route for admin/{controller}/{action}/{id}. I'm at a URL like:
/admin/release/push/255
In that view I'm using:
#Html.AnchorLink("Confirm", "Confirm")
AnchorLink is rendering a link without the current request {id} included, ie. /admin/release/confirm! If I inspect the RouteValues I can see {id} is in there. If I explicity pass in the route values from teh current request, as in:
#Html.AnchorLink("Confirm this release", "Confirm", Url.RequestContext.RouteData.Values)
Then it works, I get the URL /admin/release/confirm/255. Why does the explicit version where I pass in the current request route values work, but the implicit one, without the route values argument, which I thought would pick up the current request route values, doesn't? I know the above is a solution, but it's ugly and there's some underlying reason why the AnchorLink without the route values isn't working as I expect?!
MVC is doing exactly the right thing here. It's not to know you require the Id parameter for your anchor link or not -- in other words its not trying anything clever to pre-parse and examine the link. It will only do that when its being rendered. And in your case without the id parameter specified somewhere its going to use the default route.
If you find yourself writing that same code all over the place you could easily extract it out into a static helper class. That can get rid of the ugliness.

How to embed multiple tags in Rails routes, like Stack Overflow

When one selects a tag on Stack Overflow, it is added to the end of the URL. Add a second tag and it is added to the end of the URL after the first Tag, with a + delimiter. For example:
http://stackoverflow.com/questions/tagged/ruby-on-rails+best-practices
How is this implemented? Is this a routing enhancement or some logic contained in the TagsController? Finally, how does one 'extract' these tags for filtering (assuming that they are not in the params[] array)?
Vojto's answer is correct, but note that you can also use Route Globbing on the server side to handle this cleanly. A route defined as /:controller/*tags will match /questions/ruby/rails/routing, and in the questions_controller, params[:tags] will be an array containing ['ruby','rails','routing']. See the Routing docs.
I think Rails doesn't mind if params contains symbols like +. That means, you can access all tags as one argument, create a route like: '/show/:tags'
Then you can access params[:tags], which will be string like 'ruby+rails'. You can simply do 'ruby+rails'.split('+') to turn it into an array.
By that you can easily append new tag to this array, and turn it back into string with my_array_with_tags.join('+').

Resources