In a GSP, is it possible to create a direct link to another GSP? I know I can use:
<g:createLink controller="user" action="foo"/>
and in UserController define the foo action to just show the corresponding GSP
class UserController {
def foo = {}
}
But is there any way I can achieve the same result without having to create the empty foo action?
Thanks,
Don
The createLink tag is geared for use with controller actions and won't do what you want it to outside of the url attribute.
You can always get to a gsp by directly: /user/foo.gsp with a combination of the link and resource tags.
<g:link url="${resource(dir:'user', file:'foo.gsp')}">user/foo.gsp</g:link>
Othewise you can create a URL Mapping that maps a request directly to a view.
class UrlMappings {
static mappings = {
"/user/foo"(view:"user/foo")
}
}
Using Grails 1.2 you can create a named URL Mapping that maps directly to a view:
class UrlMappings {
static mappings = {
name userFoo: "/user/foo"(view:"user/foo")
}
}
and then use it with the link tag:
<link:userFoo>User Foo</link:userFoo>
or
<g:link mapping="userFoo">User Foo</g:link>
There's a uri attribute that's undocumented , but you can see it in the source:
link
HTH
As of Grails 2.x, this is not possible. The ability to link directly to a .gsp was a security flaw that could be used to avoid the #Secured annotation. The URL mapping method does still work though as seen in #Colin Harrington's answer.
See: GRAILS-7542: Views are accessible via a URL pattern
Related
Currently using grails 4.0.3.
I'm trying to generate a link to a controller action using a simple <g:link> tag:
<g:link controller="myController" action="myAction" params="[someParam:'myValue']">Link text</g:link>
In my UrlMappings file, I have this controller mapped to a common URL for external calls. This mapping forces some parameters that I want forced when coming to this mapping:
class UrlMappings {
static mappings = {
"/service/someExposedUrl" {
controller = "myController"
action = "myAction"
someParam = "defaultValue"
}
}
}
However, the link that gets written to the page in my application gets written using the UrlMapping definition.
http://serverUrl/service/someExposedUrl?someParam=<ignored>
instead of
http://serverUrl/myController/myAction?someParam=myValue
In this case, the parameters are ignored on the /service URL because they're hard-coded in the UrlMapping.
Is there a way to force grails to link to the specified controller/action instead of the mapping?
Up front caveat: I have not tested this for this specific situation, though I have used these pieces individually. Second caveat: I would not be remotely surprised to learn there's an even better way to do this...grails has a lot of options sometimes!
You should be able to create a named mapping in your UrlMappings, then reference that in your createLink.
UrlMappings:
name arbitraryName: "/myController/myAction" {
controller = "myController"
action = "myAction"
}
Link:
<g:link mapping="arbitraryName" params="[someParam:'myValue']">Link text</g:link>
You may be able to get what you need with a combination of Custom URL mapping and the exclude keyword in the original URLMappings.
Create MyControllerUrlMappings. This guide gives several examples of different ways of writing them out. I found it helpful.
class MyControllerUrlMappings {
static mappings = {
// Url Mappings specific only to this controller
}
}
https://guides.grails.org/grails_url_mappings/guide/index.html#_multiple_urlmappings_files
Your app will still be running the original UrlMappings file though. So you'll have the new custom Url mappings and the default ones. To fix that you can exclude your controller and it's methods in the original UrlMappings file.
class UrlMappings {
static excludes = [
"/myController",
"/myController/*"
]
static mappings = {...}
...
Not as elegant as I'd like, but in a similar situation this is how I got it working.
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>
I have a controller inside a plugin called TextController with an action called index
I then have a view inside the calling application called test-plugin.gsp with the following include tag:
<g:include controller="text" />
This works great. The problem is that the plugin's controller actually needs to identified by a package-like name, such as: com.foxbomb.fxportal3.components.text, and I need to reference it as such. So my thinking us to try and have a URL mapping for the plugin, such as:
"/components/com.foxbomb.fxportal3.components.text/" {
controller = "text"
action = "index"
}
I also don't know how to create an include in the calling application to try and call that URL, something like (I know you don't get a URL attribute):
<g:include url="/components/com.foxbomb.fxportal3.components.text"/>
In other words, I want to include a controller / action by its mapping as opposed to its controller / action name.
<g:include> doesn't allow a url attribute, which surprises me, but looking at the source of the <g:include> tag it should be possible to implement this in your own taglib fairly easily (untested):
import org.codehaus.groovy.grails.web.util.WebUtils
class IncludeTagLib {
def grailsUrlMappingsHolder
def includeUri = { attrs, body ->
def mapping = grailsUrlMappingsHolder.match(attrs.uri)
out << WebUtils.includeForUrlMappingInfo(request, response, mapping,
attrs.model ?: [:])?.content
}
}
You'd say <g:includeUri uri="/components/com.foxbomb.fxportal3.components.text"/> in your GSP.
So for instance, say i have an API on a webapp, and i wish to use the same controllers and actions in the API as the rest of the webapp.
In my urlmappings file i have
"/api/$version/$apiKey/$controller/$acion/$id?"
and i also have a mapping like this:
"/blog/$year/$month/$day/$action" {
controller = 'blog'
}
Now the question is, can i somehow prefix the api urlmapping to the blog urlmapping so i can benefit from the $year, $month, $day variables? in such a way that a GET request to the following url would be valid:
GET /api/0.1/bs23mk4m2n4k/blog/2001/01/05/list
or am i forced to do the following request instead?
GET /api/0.1/bs23mk4m2n4k/blog/list?year=2004&month=01&day=05
Need help from an urlmappings GURU or a groovy runtime urlmappings maniuplation WIZARD :)
I want a solution that can reuse existing non-api urmappings, instead of having to redeclare them with the api path as a prefix.
You could have an ApiController strip off the api parameters, then redirect to the blog controller. For example:
"/api/$version/$apiKey/$rest**" {
controller:'api'
action:'default'
}
import org.codehaus.groovy.grails.web.util.WebUtils
class ApiController {
def grailsUrlMappingsHolder
def default = {
// validate apiKey, etc
WebUtils.forwardRequestForUrlMappingInfo(request, response, grailsUrlMappingsHolder.match("/${params.rest}"))
}
}
The API controller has access to the version and apiKey params, and passes on the rest of the params to be processed by the blog controller's UrlMapping.
I think you want to use embedded variables. Check the url mapping reference: http://grails.org/doc/latest/guide/single.html#6.4 URL Mappings
just add the following mapping:
static mappings = {
"/api/$version/$apiKey/$controller/$year/$month/$day/$action"()
}
now you can use this url for example:
http://localhost:8080/api/0.1/bs23mk4m2n4k/blog/2001/01/05/list
now you get redirected to the list action in the blog controller.
there you can use params to show the parameters from the url (as defined in the mapping).
ex.
params.version
I had somewhat the same problem, solved it using named url mapping: http://www.grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.4.9%20Named%20URL%20Mappings
Hope this helps!
in urlMapping:
name blogWithYear:"/api/$version/$apiKey/$controller/$year/$month/$day":{
controller = 'blog'
action = 'youraction'
}
<g:link mapping="blogWithYear" params="[$version:'0.1', ....., '$year: 2011']">
Show blog
</g:link>
With g:link you can now compile the url however you want, adding parameters.
In grails, I have a link like /myapp/questions/all
The all is a parameter (all, replied, ...) passed to my controller.
I have a form to search question depending of type : in all, in replied, ...
In the search form, I have an hidden field to pass parameter.
But the url displayed is /myapp/questions/ ans not /myapp/questions/all
So I tried with url : url="[action:'question', controller:'mycontroller', params:['monparam':'${mavariable}']]"
but it's not working.
Any idea ?
Thanks
You can do it like this:
class UrlMappings {
static mappings = {
name nameOfTheMapping: "/question/$para/" {
controller = "mycontroller"
action = "question"
}
...
Then you can access the mapping by:
<a href='${createLink(mapping: 'nameOfTheMapping', params: [para: para.encodeAsUrl()])}' title='test'>Test</a>
The above code is created in my taglib, so it maybe a little different if you want to use it in a view.
I don't completely understand your question, but it seems you are not following the grails convention. the url is of the form
/app/controller/action
so grails is interpreting the 'all' part of your url as the action to invoke on the questions controller (what I got from your 'link like /myapp/questions/all').
Where I got confused was with your url specification.
url="[action:'question', controller:'mycontroller', params:['monparam':'${mavariable}']]"
Based on that, you should have a controller called 'mycontroller', with an action called 'question' on it. The url you will see in the browser would be
/app/mycontroller/question?monparam:whatever
See here for details on controllers in general.
You need to edit grails-app/conf/UrlMappings.groovy and create a mapping to the controller that omits the action. (since you're handling this all within one action)
something like
"/questions/$question_type" (controller: 'questions', action: 'your_action')
where "your_action" is the name of the action that is processing these requests.
Then in QuestionsController.groovy:
def your_action = {
// use question_type as needed
def questions = Questions.findByQuestionType(params.question_type)
// etc.
}
You can do a variety of things to affect the mapping of urls to requests, check out the UrlMapping section in the Grails User Guide.