How to do proper data binding in Grails - grails

I'm trying to do standard flow with adding entity to DB. Flow should look like this:
User opens link example.co/connection/putForm
edit all fields
submit (POST) to example.co/connection/put
if no errors then he is redirected to ../conncetion/index otherwise he should see previous form with all fields filled (step 2) and error message
For now my code looks like this:
def putForm() {
[
providers: Provider.findAll(),
cities : City.findAll()
]
}
#Transactional
def put() {
// not important part of parsing fields from params
def provider = Provider.get(params.provider)
def startTime = parseStartTime(params)
def path = parsePath(params)
def departurePlace = params.departurePlace
def connection = new Connection(provider: provider, startTime: startTime, departurePlace: departurePlace, path: path)
if (connection.save()) {
redirect controller: 'connection', action: 'index', params: [addedConnection: connection.id] // this part is OK
} else {
render view: 'putForm', params: params, model: [connection: connection] // this sucks... look below
}
}
The problem is that I need to render view putForm but from link .../connection/put. This cause problem that after this render all text fields are empty (step 4 above). Also I have ugly link.
Does Grails has any pattern for this common situation?
PS I cannot use scaffolding.

You're not that far off.. try this:
def putForm() {
[
providers: Provider.findAll(),
cities : City.findAll(),
connection: new Connection() // everything defaulted to empty or whatever you want the default to be
]
}
#Transactional
def put( Connection connection ) {
// NOTE: by putting the connection as the parameter to this action,
// all params.X that match a property X in the connection will auto-
// populate, even the Provider, assuming the value of params.provider.id
// is the id of a provider or blank (in which case
// connection.provider will be null.
// Skip this now
//def provider = Provider.get(params.provider)
//def startTime = parseStartTime(params)
//def path = parsePath(params)
//def departurePlace = params.departurePlace
//def connection = new Connection(provider: provider,
// startTime: startTime, departurePlace: departurePlace, path: path)
if (connection.save()) {
redirect controller: 'connection', action: 'index',
params: [addedConnection: connection.id] // this part is OK
} else {
render view: 'putForm', model: [
providers: Provider.findAll(),
cities : City.findAll(),
connection: connection]
}
}
The thing you need now is to make sure your putForm.gsp actually uses the values you sent down. You should put in things like:
<g:input name="path" type="text"
value="${fieldValue( bean:connection, field:'path' )}" />
and
<g:select name="provider.id" from="${providers}" // note the .id in places here
value="${connection.provider?.id ?: ''}"
noSelection="['':'None']"/>
Note that these will populate with whatever is in the connection sent down each time the page is rendered. So the first time it'll just have the default values, and if it has to rerender due to errors, it'll have the connection values that failed validation.
Hope this helps.

Related

Grails/SpringSecurity core and customizing logout behaviour

I'm using grails 2.3.7 with SpringSecurityCore 2.0 .. I have two separate signon screens tailored for specific devices with the appropriate one triggered by accessing a specific controller. To do this I customized the loginController ..
/**
* Show the login page.
*/
def auth() {
def config = SpringSecurityUtils.securityConfig
if (springSecurityService.isLoggedIn()) {
redirect uri: config.successHandler.defaultTargetUrl
return
}
String whereFrom = session.SPRING_SECURITY_SAVED_REQUEST.requestURI
def rdt = whereFrom.contains('RDT')
// Redirect for RDT as required ..
String view = rdt ? 'rauth' : 'auth'
String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
session.rdt = rdt
render view: view, model: [postUrl: postUrl,
rememberMeParameter: config.rememberMe.parameter]
}
which seems to work well .. On logout I want again to redirect to an appropriate screen .. I'm trying to use the session attribute I store on login along with a (admittedly old) link I found (http://grails.1312388.n4.nabble.com/Parameter-quot-logoutSuccessUrl-quot-in-spring-security-core-td2264147.html) to redirect back to an appropriate page ..
/**
* Index action. Redirects to the Spring security logout uri.
*/
def index() {
if (!request.post && SpringSecurityUtils.getSecurityConfig().logout.postOnly) {
response.sendError HttpServletResponse.SC_METHOD_NOT_ALLOWED // 405
return
}
// TODO put any pre-logout code here
def rdt = session.rdt
session.rdt = null
// redirect uri: "/j_spring_security_logout?spring-security-redirect=$logoutUrl"
if (rdt) {
def link = g.createLink(controller: "RDT")
def redirectUrl = "${SpringSecurityUtils.securityConfig.logout.filterProcessesUrl}?spring-security-redirect=${link}"
redirectStrategy.sendRedirect request, response, redirectUrl
} else {
redirectStrategy.sendRedirect request, response, SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
}
response.flushBuffer()
}
Both options return me to the 'default' auth login screen and not my alternate rauth one even with the addition of the extra parameter .. How can I route back to an appropriate screen ?? Thanks
In the end I manually set the session variables to null, invalidate the session and a standard redirect ... works ..

Dart lang, manipulating server returned JSON data in the client

I want to check the user log in parameters, and if the parameters accepted, I want the server to send back to the client both the name and roles of the user, to be saved in the SeassonStorage for further usages.
my server side code is:
....
....
var users = <Map>[];
var logged = <Map>[];
....
....
.then((_) {
for (var user in users)
if(_theData['userName']==user['Alias'] && _theData['password']==user['Password'])
{
userFound=true;;
logged.add({
"Alias":user['Alias'],
"Roles": user['Roles']
});
}
})
.then((_) {
if(userFound == true)
res.write(JSON.encode(logged));
else
res.write('sorry, unknown loggin');
res.close();
});
in the client side, I've:
....
....
if(request.responseText != 'sorry, unknown loggen'){
server_msg.innerHtml='Welcome';
print(request.responseText);
print(JSON.decode(request.responseText));
var FonixLogin = JSON.decode(request.responseText);
print(FonixLogin['Alias']);
print(FonixLogin['Roles']);
Storage sessionStorage = window.sessionStorage;
sessionStorage['FonixAlias'] = FonixLogin['Alias'];
sessionStorage['FonixRoles'] = FonixLogin['Roles'];
....
the output I get is:
[{"Alias":"Admin","Roles":"admin"}]
[{Alias: Admin, Roles: admin}]
Exception: Illegal argument(s): Alias login.dart:66login_Element.onData
Why mistake I made here, so that the returned data is not saved properly in the
FonixLogin is a List and you access it like a Map.
Try print(FonixLogin[0]['Alias']);

Unable to implement Grails-jaxrs multipart file upload integration Test

I am using grails-jaxrs for exposing an api which accepts multipart/form-data..
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(['application/json'])
#Path('/addMessage')
ChatMessage addChatMessageWithAttachment(#Context HttpServletRequest req) {
log.debug "> addChatMessageWithAttachment"
def fileStores = []
def chatMessage
GrailsWebRequest request = WebUtils.retrieveGrailsWebRequest()
def params = request.getParams()
if (!(params.messageBody.length() > 0)) {
log.error("Empty message body")
throw new LocalisedException(ErrorCode.CHAT_MESSAGE_CREATE_FAILED)
}
}
The implementation is working properly as expected. I am able to send form-data (with file and other parameters successfully.
Now I am trying to implement integration test for above logic.
I am using IntegrationTestCase to achieve this.. so my code snippet is as below:
class ChatMessageResourceV1Tests extends IntegrationTestCase{
//other implementation and setup ommited
#Test
void "Create new chat message for event id - customer user"() {
def headers = ['Content-Type': 'multipart/form-data', 'Accept': 'application/json']
def data = "My message..."
def cm = new ChatMessage(messageBody: data)
def content = "{'eventId':'$event.id','messageBody':'My message...'}"
sendRequest("/api/v1/chatMessage/addMessage", 'POST', headers, content.bytes)
assertEquals(200, response.status)
}
}
When I run the test.. I can see the call reaches inside the API method.. But however, the parameter messageBody is coming as null and exception is being thrown.
I have tried every possible combination of test.. But no luck.
Any help would be appreciated.

Grails update database row exception

I am using grails,and i have web application.in which when call for update user profile,then i have service for it,in which i set current user properties by request parameters
user.properties = params (params-request parameters),
and in my user domain class i have onChange method(of audit plugins).
So when this method called after setting properties to user profile when control goes to user domain onChange method it gives error
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.web.User#3].
I am still finding solution how to update row.
Thanks in advance.
//userController update method -
def user = User.get(params.id)
user.properties = params
user.save(flush:true)
//and in user domain onChange method-
def onChange = { oldMap,newMap ->
try{
Msg.append("Your profile has been updated successfully with the following changes: ");
oldMap.each({ key, oldVal ->
if(oldVal != newMap[key]) {
if(key =="firstName" || key =="gender" || key =="lastName" || key =="phoneNo" || key =="city"){
Msg.append(" * $key changed from $oldVal to " + newMap[key])
}
}
sendMail(Msg,newMap.email)
})
}
}
After sending email it gives an error.
I think if you try to set all the fields on the user object, then it will work:
def user = User.get(params.id)
user.refresh()
user.firstName= params.firstName
user.lastName= params.lastName
user.gender= params.gender
user.phno= params.phno
user.city= params.city
if(user.save(flush:true, failOnError:true)){
// Now send success email
}
Now it should work.
I think your params map is having id as a property and on setting
user.properties = params
It tries to set id for the user object, that's why you are getting the issue.

Automatic language detection by browser

How can I detect the language of the browser and automatically display the correctly localized version of my grails website depending on that value.
I put this in to Index action
Locale locale = new Locale(params.lang)
cookieLocaleResolver.setLocale(request, response, (Locale)
session.getAttribute('locale'))
{
render controller: "home", action: "index"
return
}
And I got exception--
Error 500: Executing action [index] of controller [socialworking.HomeController] caused exception: null
Servlet: grails
URI: /socialworking/grails/home.dispatch
Exception Message:
Caused by:
Class: Unknown
First off, you should put that in a filter in grails-app/conf directory. Create a filter if you don't already have one.
MyFilters.groovy
class MyFilters {
def filters = {
setLocale(controller:'*', action:'*') {
before = {
// Your logic here
}
}
}
}
Your logic here could look in many ways, but here is a try:
String langToSet = 'en';
if ( params.lang && params.lang in validLanguages )
langToSet = params.lang;
else if ( session.lang ) {
langToSet = session.lang;
}
else if ( ... ) // Cookie lang is set ( User might have accessed the site before and you have stored their preferred lang )
// Get cookie lang
Locale locale = new Locale( langToUse)
org.springframework.web.servlet.support.RequestContextUtils.getLocaleResolver(request).setLocale(request, response, locale);
// Set the cookie lang
...
// We set the session lang
session.lang = langToSet
Note that the above is not a complete implementation but it is almost. The cookie stuff and validLanguages you should be able to figure out what they do.
I hope that helps!

Resources