how can i redirect to the same state more than one time using web flow
ex:
on('submit'){
def destinationInstance = Destination.get(params.destination)
def destinationGroupsInstance = DestinationGroup.get(params.destinationGroups)
def h = destinationInstance.addToDestinationGroups(destinationGroupsInstance)
}.to('flowList')
what i need is how to enter to this state more than one time until destinations ends
thx
on('submit'){
def destinationInstance = Destination.get(params.destination)
def destinationGroupsInstance = DestinationGroup.get(params.destinationGroups)
def h = destinationInstance.addToDestinationGroups(destinationGroupsInstance)
}.to{
(condition or while loop or for loop)
if success then
return "<state name>"
else
return "flowList"
}
Reference:
http://livesnippets.cloudfoundry.com/docs/guide/2.%20Grails%20webflow%20plugin.html
Well, you'd probably have something like the following code, which is untested but may give you a general idea.
def destinationFlow = {
initialize {
action {
flow.destination = Destination.get(params.id)
}
on('success').to 'destinationList'
}
destinationList {
render(view: 'destinationList')
on('addDestination') {
def destinationGroup = DestinationGroup.get(params.destinationGroupId)
flow.destination.addToDestinationGroups(destinationGroup)
}.to 'destinationList'
on('finish').to 'done'
}
done {
flow.destination.save()
redirect(...) // out of the flow
}
}
You'll need buttons on your destinationList view that invoke the 'addDestination' or 'finish' actions. See the WebFlow documentation and Reference Guide.
Related
I'm trying to add new functionality, without refactoring the entire code. Actually the code calls msg.typeOfMsg('msg'), but I want to add validation when it comes true change all the typeOfMsg to a specific type:
def specialRule = true
def message = changeMessageType()
def changeMessageType() {
def toInform = { def message -> thePath.toChange.inform(message) }
return specialRule ? [reprove : toInform, approve : toInform] : thePath.toChange
}
println(message.reprove('Standart reprove message')
This is the solution I found, it works, but I have a lot of message types and custom message types, there's some way to dynamically change all calls to inform, without refactoring all the code to calls something like message(typeOfMessage, message)?
-----Edit-----
Here's a runnable version
def message = changeMessageType()
def changeMessageType() {
def originalPath = new OriginalPath()
def specialRule = true
def toInform = { def message -> originalPath.inform(message) }
return specialRule ? [reprove : toInform, approve : toInform] : originalPath
}
message.approve('Standart reprove message')
class OriginalPath {
def reprove(message) {
println "Reprove: ${message}"
}
def approve(message) {
println "Approve: ${message}"
}
def inform(message) {
println "Inform: ${message}"
}
}
I have one action in my controller that upload csv file with list of numbers.
Now the process is first I need to delete existing data from the table on certain condition then insert fresh data.
My snippet code is as follows..
Controller:
#Transactional
def uploadFile() {
if(!params?.updateExisting){
println "Going to call service to delete records"
myService.deleteNumbers()
def newList = Number.findAllByDeleted(false)
println "NEW LS:"+newList
//HERE I'm GETTING BLANK
}
def file = request.getFile("fileCsv")
file.inputStream
.splitEachLine(',') { fields ->
Number.withNewTransaction {
def number = fields[0]?.toString().replaceAll(" ","").replaceAll("-","")
Number numberInstance = new Number()
def numberExist = Number.findAllByNumberAndDeleted(number, false)
//HERE NUMBER IS STILL EXIST
if(!numberExist){
numberInstance.number = number
numberInstance.save(flush:true)
count++
}else{
println "Number exist: "+number
}
}
}
redirect(uri:'/number/list')
}
myService:
#Transactional
def deleteNumbers(){
Number.findAll().each {
it.deleted = true
it.save(flush: true)
}
}
After calling service method deleteNumbers I'm getting blank list NEW LS:[], But then def numberExist = Number.findAllByNumberAndDeleted(number, false) returns me a number means already exist.
Thanks..
Try removing Number.withNewTransaction closure. Your code should work..
I have a filter that is applicable for all controllers and actions
all(controller:'*', action:'*')
If a certain condition is met, I am trying to redirect the user to another page. But I am getting the above stated error. I inserted some logs to see if the filter is being applied or not and I noticed that the
if(condition){} block was being executed multiple times and hence I believe the error is occurring.
Please let me know how I can overcome this. Thank you.
I have code, I hope this help you
def filters = {
sessionCheck(controller: '*', action: '*') {
before = {
if(!(controllerName=="valueSet" && (actionName=="MATReleases" || actionName=="downloadReleases"))) {
if ("your condition") {
def url =new ApplicationTagLib().createLink(controller:'router',action:'sessionExpired')
render(status: 500, contentType: 'text/html', text: "<script>var sessionExpired ; window.location.href='${url}';</script>")
return false
}else{
}
} else {
println "else part"
}
}
}
}
I have some widgets in my application. I want to load them in a single page. It works always when loaded sequentially,but fails(throws exception-java.lang.IllegalStateException-Cannot ask for request attribute - request is not active anymore!) when loaded in parallel. Am I missing something ? Is there any other way to load these in parallel? Please suggest. Here is my code snippet
class TestController {
def widget1() {
render "Widget 1"
}
def widget2() {
render "Widget 2"
}
}
class ManagerController {
def loadSequential(){
def data = [:]
data['view1'] = g.include(action: 'widget1', controller: 'test')
data['view2'] = g.include(action: 'widget2', controller: 'test')
render data['view1']
render data['view2']
}
def loadParallel(){
def data = [:]
PromiseMap pm = new PromiseMap()
pm['view1'] = { g.include(action: 'widget1', controller: 'test') }
pm['view2'] = { g.include(action: 'widget2', controller: 'test') }
def result = pm.get()
render result['view1']
render result['view2']
}
}
Here's my 2p on this matter.
We've tried really hard to make Grails render pages in parallel but we couldn't make it work. After digging really deep we simply found that Grails is not ready for this kind of stuff. It's build in a way where rendering is always thread-exclusive.
I'd say it's all due to the org.codehaus.groovy.grails.web.pages.GroovyPageOutputStack that is not ready for a concurrent access.
I'll watch this space just in case someone managed to make it work.
Try this:
import static grails.async.Promises.*
...
def loadParallel() {
task {
def data = [:]
PromiseMap pm = new PromiseMap()
pm['view1'] = { g.include(action: 'widget1', controller: 'test') }
pm['view2'] = { g.include(action: 'widget2', controller: 'test') }
def result = pm.get()
render result['view1'] + result['view2']
}
}
In the loadSequential() example you are not loading response sequentially, but concatenating two views into a single response. Parallel rendering should be a client side job. See for example how Lift does it with jQuery.
My site has urls like 'http://someRandomUsername.mysite.com'.
Sometimes users will try urls like
'http://www.someRandomeUsername.mysite.com'. I'd like to have some
logic in my url mappings to deal with this.
With the mappings below when I hit the page , with or without the
unneeded www, I get:
2012-03-01 14:52:16,014 [http-8080-5] ERROR [localhost].[/ambit] -
Unhandled exception occurred whilst decorating page
java.lang.IllegalArgumentException: URL mapping must either provide a
controller or view name to map to!
Any idea how to accomplish this? The mapping is below.
Thanks!
Jason
static mappings = {
name publicMap: "/$action?/$id?" {
def ret = UrlMappings.check(request)
controller = ret.controller
userName = ret.userName
}
}
static check =
{ request ->
def tokens = request?.serverName?.split(/\./) as List ?: []
def ret = [controller:'info']
if(tokens.size() > 3 && token[0] == 'www')
{
ret.userName = tokens[1]
ret.controller = 'redirect'
ret.action = 'removeWWW'
}
else if(tokens.size() == 3)
{
ret.userName = tokens[0]
ret.controller = 'info'
}
return ret
}
Honestly, like DmitryB said, the best way to do this is via the web server, whether it's IIS, Apache, or Tomcat.
Having said that, I feel the best way to accomplish this in Grails would be using filters.
You could create something like this in your ~/conf directory:
public class StripFilters {
def filters = {
stripWWWFilter(controller: '*', action: '*') {
before = {
def tokens = request.serverName.tokenize(/\./) ?: []
if(tokens.size() > 3 && tokens[0] == 'www') {
def url = request.request.requestURL.toString().replace('www.', '')
redirect([url:url, params: [userName: tokens[1]], permanent: true])
return false
}
}
}
}
}
This should do the trick.