Flash message display grails - grails

Can I do something like this inside controller action
def update(){
if(certain validation fails )
//flash message to be visible
[domainInstance:originalDomainInstance,flash.message : "message(code:'default.some.code.label', default:'Please provide your validation err msg.' )"]
}
The above throws syntax error.
I am still trying to fix the syntax. Is it alrite to send the flash message in this way ?

Grails controller returns model which is in simple case just map (map with domainInstance in your case). flash is property which is available in controllers.
def update(){
if(certain validation fails ) {
flash.message = message(code: 'default.some.code.label', default: 'Please provide your validation err msg.')
}
[domainInstance: originalDomainInstance]
}
If you would to pass message in model map the syntax should look like below:
[domainInstance: originalDomainInstance, myMessage: message(code: 'default.some.code.label', default: 'Please provide your validation err msg.')]
Useful links: flash and models and views in Grails.

Related

Model in Grails Controller Tests is Null/Empty

I recently created a new controller in a pretty big app, (note: we just upgraded from Grails 2.0.3 to 2.3.7) and the created tests have all been failing inexplicably. Most of my errors consist of the model being [:] after a controller call. And therefore any methods on that model being null. I get stuff like:
groovy.lang.MissingMethodException:
No signature of method:
TransitionController.save() is applicable for argument types: (Transition)
values: [null] Possible solutions: save(), wait(), show(), any(),
wait(long), raw(java.lang.Object) at TransitionControllerSpec.Test the
save action correctly persists an instance(TransitionControllerSpec.groovy:45)
I have tried explicitly assigning the model by doing:
def model = controller.delete()
def model = controller.update()
//....
But I get the same result, an empty model map and null values if I try to access it.
As per this article (https://jira.grails.org/browse/GRAILS-8462) I could also try accessing the model by doing:
def model = controller.modelAndView.model
But this did not work for me either, producing the same results.
Any ideas on what might be happening?
Edit: Here are the first couple of tests
package com.hey.how.are.ya
import grails.test.mixin.*
import spock.lang.*
import org.junit.*
#TestFor(TransitionController)
#Mock(Transition)
class TransitionControllerSpec extends Specification {
def populateValidParams(params) {
assert params != null
params['reason'] = 'just cuz'
}
void "Test the index action returns the correct model"() {
when:"The index action is executed"
controller.index()
then:"The model is correct"
!model.transitionInstanceList
model.transitionInstanceCount == 0
}
void "Test the create action returns the correct model"() {
when:"The create action is executed"
controller.create()
then:"The model is correctly created"
model.transitionInstance!= null
}
//...grails generated tests here
}
Edit: Here's an interesting case! If I do:
void "Test the create action returns the correct model"() {
when:"The create action is executed"
def model = controller.create()
def inst = new Transition()
println "${model}"
println "${model.transitionInstance}"
then:"The model is correctly created"
model.transitionInstance != null
}
Then I get this as output:
[transitionInstance:null]
null
But the test passes. This only happens with create. What is going on??
Edit: Adding code for create and save
def create() {
[transitionInstance: new Transition(params)]
}
def save() {
def transitionInstance = new Transition(params)
if (!transitionInstance.save(flush: true)) {
render(view: "create", model: transitionInstance: transitionInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'transition.label', default: 'Transition'), transitionInstance.id])
redirect(action: "show", id: transitionInstance.id)
}
Edit: I can't spend too much time on this, but I'm pretty sure the problem is discrepancies between the controller generated and the test created. For what it's worth I was running version 2.0.2 of the scaffolding plugin and grails 2.3.7. I'm gonna throw out the tests created by the command and start from scratch, thanks for the help!
I had the same issue but solved it like following:
Inside the controller method:
render view: "_myTemplate", model: [instance: myInstance]
So the controller, still renders the template and inside the test spec I can test
assert(model.instance = myExpectedInstance)

what is version parameter in generated controller's update method

I am doing a sample applications in grails I created a Sponsor domain class, then I generated its corresponding controller which is
class SponsorController
{
...
def update(Long id, Long version){
def sponsorInstance = Sponsor.get(id)
if (!sponsorInstance) {
flash.message = message(code:'default.not.found.message',args:message(code:'sponsor.label',
default: 'Sponsor'),
id
])
redirect(action: "list")
return
}
if (version != null) {
if (sponsorInstance.version > version) {
sponsorInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[
message(code: 'sponsor.label', default: 'Sponsor')] as Object[],
"Another user has updated this Sponsor while you were editing")
render(view: "edit", model: [sponsorInstance: sponsorInstance])
return
}
}
sponsorInstance.properties = params
if (!sponsorInstance.save(flush: true)) {
render(view: "edit", model: [sponsorInstance: sponsorInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [
message(code: 'sponsor.label', default: 'Sponsor'),
sponsorInstance.id
])
redirect(action: "show", id: sponsorInstance.id)
}
when I generated a controllers it generated list,show,save,create,edit and update methods. I understood all the methods code but I am little confused in update's method code in which it took two parameters id and version so my question is what is version here and what is the purpose of using version here
version is added to each domain class by default and is used to implement optimistic locking. Consider the following scenario
User A retrieves an instance of domain class
User B retrieves an instance of domain class
User A updates the instance
User B updates the instance
If we simply allow user B's instance to persist he'll effectively overwrite the changes made by A. In some applications this might be OK, but in others, we might want to tell user B that the object has changed since he read it, and show him the changes instead of overwriting user A's update.
The version property is how this scenario (known as a "dirty write") is detected, i.e. it is used to check that the version of an object that was read is the same version that is currently in the database. Each time an update is made to an object, the version column is incremented.

Grails: How to dynamically change method signature in scaffolded code depending on Domain id type?

I'm trying to build a grails (2.1.0) application on top of a legacy database. It has a ton of tables, and I'd like very much to use only dynamic scaffolding. The issue is that some of the tables have a string as primary key, but template code in src/templates/scaffolding/Controller.groovy for e.g. show is
def show(Long id) {
def ${propertyName} = ${className}.get(id)
if (!${propertyName}) {
flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), id])
redirect(action: "list")
return
}
[${propertyName}: ${propertyName}]
}
For the string keys, this seems to turn the string into null, and the get fails with the error $Domain not found with id null.
If I run a generate-controller and change the signature to def show(String id), it works as expected.
So, is there a way to inspect the domain class at "dynamic scaffolding time" and write the method accordingly?
Within the controller template you have a domainClass variable that gives you access to the GrailsDomainClass representing the class for which you are generating the controller, so you can do something like this (and likewise for edit, update and delete):
def show(${domainClass.identifier.type.name} id) {
which should generate def show(java.lang.Long id) or def show(java.lang.String id) as appropriate.

Grails: Refresh view after submit

I've seen various answers to similar questions, but not for this specific case:
I have a Grails gsp with several fields and a submit button. I want to enter a value in the first field, click submit, and have the controller return values into the remaining fields (including the original entry field). I want to do this with a simple page refresh (no AJAX) and it does not involve a database. I have it working fine with two gsp pages that are identical but have different names. I just call the first one, enter the value, and have the submit action point to the second. But I would like to be able to do it with a single gsp. A simplified version of my controller looks like this:
class CalculatorController {
def index = {
redirect(action: "input")
}
def input= {}
def calculateValues = {
def inputString = params.enterValue
def value2 = 'You entered something on the page'
[field1: inputString, field2: value2]
}
}
you need to have all of logic inside of the same closure if you want to use only one gsp. Test if the params are passed in and return the correct vals
Actually you don't need to have all of your logic in the same closure. Simply specify the view template to use in calculateValues...
def calculateValues = {
def inputString = params.enterValue
def value2 = 'You entered something on the page'
render(view: 'input', model: [field1: inputString, field2: value2])
}
By using the render method you can have multiple controller action reuse the same gsp view.

Returning true or error message in Ruby

I'm wondering if writing functions like this is considered good or bad form.
def test(x)
if x == 1
return true
else
return "Error: x is not equal to one."
end
end
And then to use it we do something like this:
result = test(1)
if result != true
puts result
end
result = test(2)
if result != true
puts result
end
Which just displays the error message for the second call to test.
I'm considering doing this because in a rails project I'm working on inside my controller code I make calls to a model's instance methods and if something goes wrong I want the model to return the error message to the controller and the controller takes that error message and puts it in the flash and redirects. Kinda like this
def create
#item = Item.new(params[:item])
if !#item.nil?
result = #item.save_image(params[:attachment][:file])
if result != true
flash[:notice] = result
redirect_to(new_item_url) and return
end
#and so on...
That way I'm not constructing the error messages in the controller, merely passing them along, because I really don't want the controller to be concerned with what the save_image method itself does just whether or not it worked.
It makes sense to me, but I'm curious as to whether or not this is considered a good or bad way of writing methods. Keep in mind I'm asking this in the most general sense pertaining mostly to ruby, it just happens that I'm doing this in a rails project, the actual logic of the controller really isn't my concern.
I would say that methods that return different types (e.g. boolean vs. string vs. numbers) under different circumstances are a bad practice.
If you have some sort of test method that wants to return details of why the test has not passed then you can return a pair of values (an Array) as follows:
def test(x)
if x == 1
return true, "x is fine"
else
return false, "Error: x is not equal to one."
end
end
and then write the section of your controller code as:
valid, message = #item.save_image(params[:attachment][:file])
if !valid
flash[:notice] = message
redirect_to(new_item_url) and return
end
If you're talking about a save_image method that will succeed the majority of the time but may fail and you want to indicate this failure and the reason then I would use exceptions e.g.
def save_image(file)
raise "No file was specified for saving" if file.nil?
# carry on trying to save image
end
and then your controller code would be along the lines of:
begin
result = #item.save_image(params[:attachment][:file])
rescue Exception => ex
flash[:notice] = ex.message
redirect_to(new_item_url) and return
end

Resources