URL and query string in Grails UrlMappings - grails

After searching for a while, I'm still not able to do the following using Grails. I want match a variable with some part of URL plus the query string.
I have the following rule in UrlMappings:
"/myservice/$url**?"{
controller = "mycontroller"
action = "myaction"
}
With this, I'm able to grab the portion of the URL that want via params.url, except the query string.
In other words, I want to grab everything that comes after /myservice/ in a variable.
I know I can get the query string with request.queryString, but I would prefer the way I'm suggesting. Maybe this is not even possible...

Related

Grails Reverse Url Mapping: Is there a way to build links based on the currently matched route?

I'm trying to build some dynamic URL mappings that are based on the domain classes of the grails project. The goal is to use a single generic controller, but the URL decides which domain is being used for processing. The problem is now, that I don't get the desired URLs when using the <g:link /> tag.
I tried the following variants to create the URL mappings:
static mappings = {
Holders.grailsApplication.domainClasses.each {
"/admin/${it.propertyName}/$action?/$id?"(controller: "admin")
}
}
static mappings = {
"/admin/$domainClass/$action?/$id?"(controller: "admin")
}
Both variants work for the actual URL matching. But I personally don't like the behavior of the reverse URL mapping by grails. In case of variant 1, the reverse mapping always resolves to the last added URL mapping for the AdminController. For case 2 I have the problem that I would have to pass the domainClass-Parameter to every link-creating call, even though it is theoretically not necessary, since the information is already present in the current request.
I know there is the possibility of using named URL mappings and then using something like <g:link mapping="mapping_name" />. The problem is that I am using some generic application-wide partial-views, where I try to only provide the necessary information for creating a link, like <g:link action="something" />.
This leads to my two questions:
Is there a possibility to get g:link to build the URL based on the matched mapping in the current request?
Is there a way to get a reference to the mapping that matched the current request, so I can implement to desired behavior myself?
You could define named mappings like
Holders.grailsApplication.domainClasses.each { dc ->
name((dc.propertyName):"/admin/${dc.propertyName}/$action?/$id?" {
controller = "admin"
domainClass = dc.propertyName
})
}
With the mapping name saved in the params you can now do
<g:link mapping="${params.domainClass}">link text</g:link>

Composite C1 routes.MapPageRoute - Directing to a page

I have been adding some custom routes which are not working
I can get this MVC route working but the problem is it simple routes directly to the view rather than the page which contains the master layout etc.
routes.MapRoute("Job-Listing", "job-detail/{category}/{title}/{id}", new { controller = "JobSearchModule", action = "JobDetail" });
I tried routing to a page which existed like following. This didn't work and simple went to a page not found.
routes.MapPageRoute("Job-Listing", "job-detail/{category}/{title}/{id}", "~/job-seekers/job-search/job-detail");
I guessed that this might be because this is not a physical path and there is some other routing going off under the hood. So I tested this by adding a Route to a physical page like follows. (this route worked)
routes.MapPageRoute("jobDetail2Route", "job-detail/{category}/{title}/{id}", "~/Text.aspx");
This got my thinking that composite c1 might have a physical URL which the C1 routing maps to. I'm sure I have seen at some point something to do with a /Renderers/Page.aspx. Does anyone know if I could somehow route to a physical page in this way?
Thanks
David
OK so some further information.
I realized I could get the the URL using /Renderers/Page.aspx?pageId=d622ab3b-2d33-4330-9e6e-d94f1402bc80. This URL works fine so I attempted to add a new route to this URL like as follows...
routes.MapPageRoute("Job-Listing", "job-detail/{category}/{title}/{id}", "~/Renderers/Page.aspx?pageId=d622ab3b-2d33-4330-9e6e-d94f1402bc80");
Unfortunately this still didn't work. I got an error on the Renderers/Page.aspx
Value cannot be null.
Parameter name: pageUrlData
Any ideas?
Rather than using the internal representation of a page URL like ~/Renderers/Page.aspx?pageId=d622ab3b-2d33-4330-9e6e-d94f1402bc80 you should use the public representation like /my/page/url.
To get the public representation from the page id you could use a method like this:
using Composite.Data;
...
public string GetPageUrl( Guid pageId )
{
using (var c = new DataConnection())
{
PageNode p = c.SitemapNavigator.GetPageNodeById(pageId);
return p.Url;
}
}
This will give you the public URL of the page with the provided id. If you are running a website with different content languages this method will automatically fetch you the URL matching the language of the page your MVC Function is running on.
Should you have the need to explicitly change the language of this URL use the overload DataConnection(CultureInfo culture) instead of the default constructor.
With the above method in place you should be able to do this:
routes.MapPageRoute(
"Job-Listing",
"job-detail/{category}/{title}/{id}",
GetPageUrl(Guid.Parse("d622ab3b-2d33-4330-9e6e-d94f1402bc80"));

stackoverflow like url redirect

I want to achieve what stackoverflow does with url.
domain.com/questions/1234/properTitle <-- fine!
domain.com/questions/1234/wrongTitle <-- redirect to domain.com/questions/1234/properTitle
But I don't want to contact the database twice.
For example, inside the question controller action, I am already querying all the info based on 1234 question Id. I do not want to redirect and lose all this information and then query again. Should I put it in TempData or something? What efficient way to handle this?
I think it's more complicated (and maybe even less efficient) to manually cache and retrieve the data in your application. Your database server probably caches the result anyway and the second query won't take very long.
Update: You can redirect to an overloaded action with the model as an argument. This could look somewhat like this:
return RedirectToAction("Action",
new {
id = 1234,
title = "properTitle",
model = myAlreadyRetrievedModel
});

URL Mapping prefix in Grails

Recently, I'm trying to migrating my application from CakePHP to Grails. So far it's been a smooth sailing, everything I can do with CakePHP, I can do it with much less code in Grails. However, I have one question :
In CakePHP, there's an URL Prefix feature that enables you to give prefix to a certain action url, for example, if I have these actions in my controller :
PostController
admin_add
admin_edit
admin_delete
I can simply access it from the URL :
mysite/admin/post/add
mysite/admin/post/edit/1
mysite/admin/post/delete/2
instead of:
mysite/post/admin_add
mysite/post/admin_edit/1
mysite/post/admin_delete/2
Is there anyway to do this in Grails, or at least alternative of doing this?
Grails URL Mappings documentation doesn't help you in this particular case (amra, next time try it yourself and post an answer only if it's any help). Daniel's solution was close, but wouldn't work, because:
the action part must be in a closure when created dynamically
all named parameters excluding "controller", "action" and "id" are accessible via the params object
A solution could look like this:
"/admin/$controller/$adminAction?/$param?"{
action = { "admin_${params.adminAction}" }
}
The key is NOT to name the parameter as "action", because it seems to be directly mapped to an action and can not be overriden.
I also tried a dynamic solution with generic prefixes and it seems to work as well:
"/$prefix/$controller/$adminAction?/$param?"{
action = { "${params.prefix}_${params.adminAction}" }
}
I didn't test it, but try this:
"mysite/$prefix/$controller/$method/$id?"{
action = "${prefix}_${method}"
}
It constructs the action name from the prefix and the method.
Just take a look on grails URL Mappings documentation part

Is it possible to have Html.ActionLink add URL params automatically?

What I'd like is for all urls to contain a certain parameter without having to pass it to the views and add it to ActionLink through the routevalues param. I have a section in my site that I want to keep track of a "return param" for all links. It works fine for forms since Html.BeginForm sets the action to the exact current url already.
So, if the page I'm at is
/MyController/MyAction/300?ReturnTo=100
and I output
Html.ActionLink("Next Screen", "MyOtherAction")
I'd like to see
Next Screen
without having to do
Html.ActionLink("Next Screen", "MyOtherAction", new {ReturnTo = Model.ReturnTo})
You could write your own HtmlHelper extension that does this by calling Html.ActionLink, and combining the query strings. Use the ViewContext to get at the current query string.
Try this:
Html.ActionLink("Next Screen", "MyOtherAction", new {Model.ReturnTo})
The link will now appear the way you want it to be.

Resources