Grails parameter passing - grails

Basically I am using the code below for debugging. It renders null and I cannot figure out the
reason. And by the way the else statement will always be executed at this point. At first I
didnt have the save method but I then thought it might fix my issue. May is have to do with
the scope of my domains? As of now I have them set to session scope:
class Info {
static scope = "session"
String name
String smokingStatus
String[] symptom
static constraints = {
}
}
else{//query did not find patient with that id
def patInfo = new Info()
patInfo.name = "Dennis"
patInfo.smokingStatus = "Former Smoker"
patInfo.symptom = ["Cough"]
patInfo.save()
redirect(action:"display", params: [patInfo:patInfo])
//redirect(action:"login")
//return to login action and
}
}
}
def display(){
render params.name
}
Thanks for any help its much appreciated.

You are assign the value of patInfo to variable name patInfo so in the display action you must use:
render params.patInfo
By example if you will use the following:
redirect(action:"display", params: [duck:patInfo])
You must use:
render params.duck

Related

Grails rejectValue - multiple checks causing ob.errors null

My domain object booking has multiple attributes that are allowed to be null, because they will be set later after the object has been saved to the db.
Part of myService.action():
booking.properties = params
if (booking.contactFirstname?.length() <= 1) { booking.errors.rejectValue("contactFirstname", "empty") }
if (booking.contactLastname?.length() <= 1) { booking.errors.rejectValue("contactLastname", "empty") }
if (booking.contactPhone?.length() <= 1) { booking.errors.rejectValue("contactPhone", "empty") }
if (booking.contactMobile?.length() <= 1) { booking.errors.rejectValue("contactMobile", "empty") }
if (booking.contactEmail?.length() <= 1) { booking.errors.rejectValue("contactEmail", "empty") }
if (booking.hasErrors() || ! booking.validate()) {
return [success: false, model: booking]
} else {
booking.save(failOnError: true)
return [success: true, model: booking]
}
My controller does:
def result = myService.action(params)
if (result.success) {
flash.success = message(code: "msg.successfullySaved")
redirect(action: "registerEventConfirmation", id: result.model.uid, params: [lang: params.lang], mapping: "paginated")
} else {
flash.error = message(code: "msg.errorSavingCheckFields")
render(view: "registerEventStep3", params: [lang: params.lang], model: [booking: result.model])
I'm using
hasErrors(bean: booking,field:'contactFirstname', 'has-error')}
to mark error fields.
If I now submit the form without any values in textfields, all fields are red, booking.errors has >0 errors.
If I submit the form after with a firstname, booking.errors is NULL and no other field is marked.
Is this a Bug? I'm with Grails 2.3.6
additional information
I visit the form, submit it empty completely
I see all form fields in red, object.errors has >0 errors (VALID)
I enter a value in the first field, firstname and submit
I see none of the form fields in red, object.errors =0 errors (INVALID)
I re-submit the form with none changes
I see all empty form fields in red, object.errors has >0 errors (VALID)
Now that I fully understand the situation and since I was having trouble sleeping I thought I give you a very concise answer so that you can hopefully make full sense and use things properly.
Firstly I know creating a validation bean sounds like it will be a lot of work so let me teach you how to do it all relatively simply and why it is my preferred method.
It is my preferred method simply because when you do
class MyController {
def myAction(Mybean bean) {
// 1. the object allowed into this save action
// are all that is available objects withing MyBean.
// If it has user define but not telephone. Then
// if telephone is passed to myAction it will fail and not recognise
// field
// When declaring Date someField or User user then the params now
// received as bean this way is now actually properly bound
// to the data / domainType declared.
// Meaning user will now be actual user or someField actually Date
}
So now to explain how to best solve this issue. When creating beans simply copy over the actual domain class from your domain folder into src/groovy/same/package in grails 2 or src/main/groovy/same/package in grails 3
Change name / class or copy as from Booking to BookingBean so it has a different name.
Add #Validateable above actual BookingBean in grails 2 or add implements to main class like Class BookingBean implements Validateable { in grails 3
Now since it is copied all the objects are identical and at this point a save from the controller would be
class MyController {
def myAction(BookingBean bean) {
Booking booking = new Booking()
// this will save all properties
booking.properties = bean
booking.save()
}
}
But you have a special circumstance and you wanted to declare a transient field in the main domain class what I would do instead is
class BookingBean {
def id
String contactFirstname
String contactLastname
boolean secondSave=false
static constraints = {
id(nullable: true, bindable: true)
contactFirstname(nullable:true) //,validator:checkHasValue)
contactLastname(nullable:true) //,validator:checkHasValue)
secondSave(nullable:true,validator:checkHasValue))
}
//use the same validator since it is doing identical check
static checkHasValue={value,obj,errors->
// So if secondSave has a value but contactFirstName
// is null then complain about contactFirstName
// you can see how secondSave gets initialise below
//typical set this to true when you are about to save on 2nd attempt
//then when set run validate() which will hit this block below
// Check all the things you think should have a
// value and reject each field that don't
if (val) {
if ( !obj.contactFirstname) {
errors.rejectValue('contactFirstname',"invalid.contactFirstname")
}
if ( !obj.contactSecondname) {
errors.rejectValue('contactSecondname',"invalid.contactSecondname")
}
//and so on
}
}
So now in your controller:
class MyController {
def save1(BookingBean bean) {
Booking booking = new Booking()
// this will save all properties
booking.whatEver = bean.whatEver
booking.save()
// you can choose to validate or not here
// since at this point the secondSave has
// not been set therefore validation not called as yet in the bean
}
//you probably have id and it should bind with actual domain class
def save2(BookingBean bean) {
booking.secondSave=true
if (!bean.validate()) {
//this is your errors
//bean.errors.allErrors
return
}
//otherwise out of that loop since it hasn't returned
//manually set each object
booking.contactFirstname=bean.contactFirstName
booking.contactSecondname=bean.contactSecondname
booking.save()
}
}
e2a side note - above should answer
well don't validate it until you have created it. Only validate it after you created the object then added a value. Alternative create a function possibly in a validation bean that you run as part of your 2nd check. This Example bean is not validated until formatRequest is called as seen here
I don't grasp the specifics of your question, so I will give some general guidance since I have just dug into this.
Don't call hasErrors() before validate(). If you do, Grails won't hand you errors from domain constraints and you will only end up with the errors you set yourself using rejectValue().
Be careful with using rejectValue(). Try to set all your errors using domain constraints. If you have sophisticated constraints use the validator syntax and obj.getPersistentValue() might be your friend once in a while.
If you still have to use rejectValue(), understand that any later calls to validate() will start from scratch and erase your prior errors. I have written a workaround for this (to be placed in your domain object) although I can't assure you it is 100% ok:
def validateWithErrors(def fields = null) {
def existingErrors = this.errors
def ret = (fields ? this.validate(fields) : this.validate())
existingErrors?.allErrors?.each { error ->
this.errors.rejectValue(error.field, error.code)
}
return (existingErrors?.allErrors ? false : ret)
}

GRAILS: findALL() vs FindBy---(params.id)

Greeting everyone,
I am trying to pass a parameters from a URL to a findAll() method.
LINE3 I use findAll() to define mouse.
LINE2 def house will bring in the parameter DELAWARE when I go to the page: http://localhost:8080/TestApp/home/county/DELAWARE
House will only show one instance instead of a list.. is there anyway to pass the url instead of ["DELAWARE"]? (please see line 3) thanks :)
def county() {
def house = Home.findByCounty(params.id) //sends only user related address to view
def mouse = Home.findAll("from Home h where h.county= ?", ["DELAWARE"]);
if (!house) {
response.sendError(404)
} else {
[house:house, mouse:mouse ]
}
}
Working Code +1 #Danilo
def county() {
def house = Home.findAllByCounty (params.id) //sends only county specified thru URL e.g. http://localhost:8080/TestAPP/home/county/DELAWARE
if (!house) {
response.sendError(404)
} else {
[house:house ]
}
}
findBy* will return at most one row, if you want to get all rows use findAllBy*
In order to understand how the URL will be used by Grails you have to have a look at conf/UrlMappings.groovy. You may find something like this:
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
}
}
this means that when you call TestApp/home/county/DELAWARE what Grails is trying to do is use the home controller (HomeController), invoking the county method (def county(){...}) and passing DELAWARE as id.
This should work correctly if inside county method of the HomeController you have:
def filteredInstances = Home.findAllByCounty(params.id)

How to access a string from one method to another in one controller?

If we have one controller, let's call it document, that has two methods, one that uploads file and another that shows the uploaded file.
I would like to define a new string in the upload method that checks the size of the file and store a specific type name inside that string.
However I would like to access that string in another method which is the list method to be able to show it.
Here is my code:
Class DocumentController {
def list() {
//Here I would like to access that String to show it on the page
[fileSizeType: fileSizeType]
}
def upload {
//define the new String variable
String fileSizeType = ""
if(fileSize < 1000) {
fileSizeType = "type1.."
} else {
fileSizeType = "type2.."
}
}
}
In the gsp page I would like to access the string this way:
<td><g:link>\${fileSizeType}</g:link></td>
I am getting this error when I try the code above:
No such property: fileSizeType for class: file_down.DocumentController
You need to redirect to the list action while passing your argument in the params.
def upload() {
// simplify with ternary expression
def fileSizeType = (fileSize < 1000) ? "type1.." : "type2.."
redirect action:'list', params:[fileSizeType: fileSizeType]
}
// in your list action
def list() {
[fileSizeType: params.fileSizeType]
}

redirect in grails

I am redirecting an uploaded image in grails like so:
Controller:
def upload() {
def f = request.getFile('myFile')
if (f == null | f.empty) {
flash.default = "file cannot be empty"
errors.getFieldError("cannot be empty")
return
}
def fName = f.getOriginalFilename()
def picture = new Picture(orgName: fName, urlOrg: "http://localhost/"+fName)
f.transferTo(new File('/Users/sagarmichael/Desktop/photoUpload/'+fName))
println("saved")
redirect(action: 'test', params: [url1:picture.urlOrg] )
}
def test(){
System.out.println(params.url1)
[url1:params.url1]
}
I would expect this to then send url1 to my view called test where I have this:
<img src="${url1}"/>
I would expect this to then show the image on screen.
I have the apache2 config set correctly and when i go to
http://localhost/<imageName>
it works correctly.
What I am getting is this in the url bar on the browser:
http://localhost:8080/FYP/profile/test?url1=http%3A%2F%2Flocalhost%2Flonglogo3.png
any ideas?
If you use the redirect method with params they will appear in the url. To omit this, you will need to think in another way to design your code.
Looking at your code, it appears that you do the upload of some image and need to show the result. I suggest you pass just the name of the image to your other method and mount the link dynamic (not always will be localhost, wright?). The output url will be:
http://localhost:8080/FYP/profile/test?image=longlogo3.png
If you need to omit the name of the image too you will have to store this in the session.
You are mixing model and URL params. If you really need to have it like this, you have to put the content of param 'url1' into the model in the test() action:
def test() {
return [ 'url1': params.url1 ]
}
I hope, you get the point, I definitely recommend to redesign the code ;-)
Try
render(view:"test", model: [url1:picture.urlOrg])
Or
chain(action: "test", model: [url1:picture.urlOrg])

Grains repetead code for actions in controllers

I have already posted this question, but i realised the aswer was not what i was looking for. Imagine this controller:
class exampleController{
def action1 = {
...
[lala: lala, lele: lele]}
...
}
def action15 = {
...
[lala: lala, lele: lele]
}
I want to be able to return in all the action in this controller the same params. Imagining this:
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
Is there any way of doing this, besides writing all the same code on all the actions? I have tried this method and it isnt working:
def action5 = {getModel()}
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]. Any suggestion please ? I have also tried filters like in here: Grails controllers repeated code for all actions
but i couldnt managed to make it work. I would apreciated a detailed explanaintion about any of the solutions if possible:p Thanks in advanced,
VA
So it's not the same model, but a model with a repeated part.
You should know that the return value is an ordinary Map.
So, return value can be constructed like return getCommonModel() + [book: currentBook] where getCommonModel() returns another Map.
If you want to return the same model from all your actions, this approach should work:
class ExampleController {
def action5 = {getModel()}
def action1 = {getModel()}
//etc.
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
If you want to return the same model and render the same view from all your actions, you could return the same ModelAndView from each action, but then I would ask why do you need separate actions if they're all doing exactly the same thing?
I don't really understand your hypothesis
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]
If your suggesting that getModel() can only return a model with a single entry, I find that very hard to believe. Can you elaborate a bit on this, or post some more information (e.g. stacktrace, unit test) that shows how/why it's not working?
Update
After reading your comments below I think I finally understand what you want to achieve, which is to append the model returned by getModel() (above) to the model returned by various other actions. Does this work:
class ExampleController {
def action5 = {
def action5Model = [foo: 'bar']
return addBookModel(action5Model)
}
def action1 = {
def action1Model = [foo2: 'bar2']
return addBookModel(action1Model)
}
//etc.
private Map addBookModel(Map model) {
def book = Book.findAllByIsbn(Isbn.get(1))
model.book = book
return model
}
}
This approach will only work when you want to add the book model within a single controller. If you want to add the book model in several controllers you can do this by:
putting addBookModel in an abstract class that the controllers extend
putting addBookModel in a class that is mixed-in with the controllers (using #Mixin)
putting addBookModel in a filter that is executed after the controller actions
If you are using exact same model in multiple pages. I would recommend you use a taglib for it.

Resources