Can Grails route requests to different controller by *method*? - grails

I have a URL that I'd like to handle with different controllers depending on the method. Is there a way to do this via UrlMappings?
Using two different mappings for the same URL doesn't work (the second overwrites the first)...

Untested, but can you try with the below mapping:
"/myurl" {
if(params.method == "doThis"){
controller = "doThis"
action = "doThisAction"
} else if(params.method == "doThat"){
controller = "doThat"
action = "doThatAction"
}
}
Assuming,
http://<appserver>/myurl?method=doThis
http://<appserver>/myurl?method=doThat
UPDATE
When referring to HTTP Methods you can use filter (where we have request available) as below:
class RoutingFilters{
def filters = {
routingCheck(uri: '/myurl/**' ) {
before = {
if(request.method == 'GET'){
redirect(controller: 'doThis', action: 'doThis')
}
if(request.method == 'POST'){
redirect(controller: 'doThat', action: 'doThat')
}
//So on and so forth for PUT and DELET
return false
}
}
}
}
provided the url mapping would look something like:
//defaulting to "doThis" or any other "valid" controller as dummy
"/myurl/$id?"(controller: 'doThis')

Related

Grails 3 How to access a namespace from an interceptor

I set up namespaces in my UrlMappings.groovy as:
"/usa_az/$controller/$action/$id?(.${format})?"(namespace: 'usa_az')
"/usa_ms/$controller/$action/$id?(.${format})?"(namespace: 'usa_ms')
Is there a way to do something like:
class NameSpaceInterceptor {
NameSpaceInterceptor(){
matchAll() //match all controllers
}
//Change the name of the view to find it in state-specific folder in views
boolean after() {
if(*controller.namespace* == 'usa_az' ){
view = "/usa_az/$view"
} else if (*controller.namespace* == 'usa_ms' ){
view = "/usa_ms/$view"
}
true
}
}
How do I find the handle to controller or more importantly the namespace in this interceptor?
I actually did something along the lines of this:
boolean before() {
if (controllerNamespace == "admin") {
}
}
in one of my interceptors, so the answer should be via controllerNamespace.

Grails 2.3.8 check url mappings for string occurence

I am trying to map the following
//localhost:8080/user/login/&debug=1
...
//localhost:8080/user/&debug=1
If there is any occurrence of string '&debug=1' then execute some-controller's action.
You can use a filter to do the redirect when required.
class DebugFilters {
def filters = {
debugCheck(controller: '*', action: '*') {
before = {
if (params.debug == '1') {
redirect(controller: 'some', action: 'debug')
return false
}
}
}
}
}
If you want to just switch between controllers and actions for a particular url mapping then you can also use a url mapping as below, instead of the filter altogether:
//UrlMappings.groovy
"/user/login" {
controller = { params.debug == '1' ? 'some' : 'user' }
action = { params.debug == '1' ? 'debug': 'index' }
// Note the use of a closure in ternary operations
// params is available in a closure (delegated)
// because it is not available in by default
}
You could use a URLMapping like this
"/**&debug=1"(controller:"defaultDebug"){
action = [GET: "show"]
}
By using the double wildcard you can catch anything that ends with &debug=1

Grails UrlMapping route to fixed controller and action

I made the following rule in my UrlMapping file and now all my controllers are matching to the ("/$username") mapping, not the first one ("/$controller/$action?/$id?").
The idea here was to list all public items from an user using a short url. It works but it breaks all others controllers.
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/$username" {
controller = 'user'
action = 'publicItens'
}
"/"(controller:'usuario', action: 'index' )
"500"(view:'/error')
}
How can I map it correctly?
solved!
I just wrote some code in the UrlMappings to create rules automatically for each controller in the application. Using this approach when the user types /appname/controllerName then the rule created automatically is considered in place of the "$/username" rule.
The critical point is that the use of ApplicationHolder which is deprecated. That can fixed writing your own ApplicationHolder.
static mappings = {
//creates one mapping rule for each controller in the application
ApplicationHolder.application.controllerClasses*.logicalPropertyName.each { cName ->
"/$cName" {
controller = cName
}
}
"/$controller/$action?/$id?"{
}
"/$username" {
controller = 'usuario'
action = 'itensPublicos'
}
"/"(controller:'usuario', action: 'index' )
"500"(view:'/error')
}
Just add /users/$username to the URL mapping. This is the simplest way how to achieve your goals.
"/users/$username" {
controller = 'user'
action = 'publicItens'
}
You could probably also exclude the user and usario controllers in the first url mapping constraints(notEqual)
http://www.grails.org/doc/latest/ref/Constraints/notEqual.html

How to redirect to external url using filters when controller does not exist in current app

I have the following filter that in app1 that is supposed to redirect to an external app (app2).
class MyFilters {
def userService
def springSecurityService
def filters = {
all(controller: '*', action: '*') {
before = {
String userAgent = request.getHeader('User-Agent')
int buildVersion = 0
// Match "app-/{version}" where {version} is the build number
def matcher = userAgent =~ "(?i)app(?:-\\w+)?\\/(\\d+)"
if (matcher.getCount() > 0)
{
buildVersion = Integer.parseInt(matcher[0][1])
log.info("User agent is from a mobile with build version = " + buildVersion)
log.info("User agent = " + userAgent)
String redirectUrl = "https://anotherdomain.com"
if (buildVersion > 12)
{
if (request.queryString != null)
{
log.info("Redirecting request to anotherdomain with query string")
redirect(url:"${redirectUrl}${request.forwardURI}?${request.queryString}",params:params)
}
return false
}
}
}
after = { model ->
if (model) {
model['currentUser'] = userService.currentUser
}
}
afterView = {
}
}
}
}
A problem occurs when the request to app1 contains a URI where the controller name does not exist in app1 (But does in app2 where I want to redirect to).
How can I redirect requests to app2 with same URI appended? (regardless if they exist in app1 or not).
I suspect filter's are not the correct solution as it will never enter them if the controller does not exist in app.
Ideally, I need a solution that can be implmented via code and not apache.
Thanks
Define a general purpose redirect controller like this:
class RedirectController {
def index() {
redirect(url: "https://anotherdomain.com")
}
}
In UrlMappings, point 404 to this controller:
class UrlMappings {
static mappings = {
......
"404"(controller:'redirect', action:'index')
......
}
}
Actually you can define all the redirect relationships here instead of deal with filter.
You can set the scope of a filter by URI as well as by controller name, try:
def filters = {
all(uri:'/**') {

is it possible to access the view state from a webflow controller action?

i have a controller that is not on webflow but need to redirect it to a weblflow. The problem is the view I need to access is inside an action of a webflow.
here is my webflow
class EditSpouseContactInfoController {
def index = { redirect(action:"editSpouseContact") }
def editSpouseContactFlow = {
start{
action {
//some codes here
}
on("success").to("editSpouseContact")
on(Exception).to("editSpouseContact")
}
editSpouseContact {
/************************************/
// Veteran Marital History Processing
/************************************/
on("addMaritalHistory"){
flow.contactInstance.properties = params
if(!flow.maritalHistoryLst){
flow.maritalHistoryLst = []
}
conversation.maritalHistoryInstance = new MaritalHistory()
conversation.maritalHistoryInstance.isVeteranMaritalHistory = false
}.to("editSpouseMaritalHistory")
}
}
here is my non weblow controller:
def addMaritalHistory={
MySession session = MySession.getMySession(request, params.id)
def caseInstance = CmCase.get(params.cmCaseIdCmCase.id as Long)
redirect(controller: "editSpouseContactInfo", action: "editSpouseContact ", id:caseInstance.id)
}
The line above works but is it possible for me to directly access addMaritalHistory inside editSpouseContact?like instead of using the above action it would be action: "addMaritalHistory"? Of course it is not working but is there a way to call that as action? thanks
The whole point of web flow is that you can't jump directly into the middle of a flow from outside it. You'll have to add some logic to the initial start state to check for certain parameters in the incoming params and jump to the appropriate state from there.

Resources