Model in Grails Controller Tests is Null/Empty - grails

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)

Related

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.

How to render the output of my action

My controller:
def getMenuItemCount(String name){
def myCount = MenuItem.countByMenuItemCategory(name)
render myCount
}
What do i call in another gsp so that myCount appears. createLink doesnt seem to work
${createLink(action:'getMenuItemCount', params: [name:ci.name])}
A model has to be returned instead of rendering it in order to access it in a gsp.
def getMenuItemCount(String name){
[ myCount: MenuItem.countByMenuItemCategory(name) ]
}
Also, (not related to question really), try to avoid using action names as get* and set*. I have seen discrepancies with that nomenclature.

Grails GORM MissingMethodException

new to groovy and stuck on this for quite some time.
Heres the method in question.
protected User currentUser() {
def user = springSecurityService.currentUser
println "In currentUser Method"
println "Is userId null?"
println user.id == null
println user.id instanceof Long
User.get(user.id)
}
And User.get is a method in the GORM package
D get(Serializable id) {
execute({ Session session ->
session.retrieve(persistentClass, id)
} as SessionCallback)
}
Im getting the error
No signature of method: User.get() is applicable for argument types: () values: []
What I dont understand is that through the println statements I verified that
user.id is not null
user.id is instanceof Long , which implements the Serializable interface.
Any idea whats happening here?
Thank you.
A possible solution could be that you have an invalid import statement. User is a very common class name so maybe you (or your IDE) have imported a different User class than you expect. The imported class might not have a get(id) method.

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.

Resources