grails - Generated instance in View definition - grails

generate-all in grails will Generate a Controller together with View (CRUD), I am trying to learn the impact of each generated block of code and now I can't seem to find the definition of {accountInstanceList} in the index.gsp.
/views/account/index.gsp
<g:each in="${accountInstanceList}" status="i" var="accountInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${accountInstance.id}">${fieldValue(bean: accountInstance, field: "firstname")}</g:link></td>
<td>${fieldValue(bean: accountInstance, field: "middlename")}</td>
<td>${fieldValue(bean: accountInstance, field: "lastname")}</td>
<td>${fieldValue(bean: accountInstance, field: "email")}</td>
<td>${fieldValue(bean: accountInstance, field: "role")}</td>
</tr>
</g:each>
From what I have learned the definition of the said instance should be included in Controller
/controller/.../AccountController.groovy
package ers
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
#Transactional(readOnly = true)
class AccountController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Account.list(params), model:[accountInstanceCount: Account.count()]
}
def show(Account accountInstance) {
respond accountInstance
}
def create() {
respond new Account(params)
}
#Transactional
def save(Account accountInstance) {
if (accountInstance == null) {
notFound()
return
}
if (accountInstance.hasErrors()) {
respond accountInstance.errors, view:'create'
return
}
accountInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'account.label', default: 'Account'), accountInstance.id])
redirect accountInstance
}
'*' { respond accountInstance, [status: CREATED] }
}
}
def edit(Account accountInstance) {
respond accountInstance
}
#Transactional
def update(Account accountInstance) {
if (accountInstance == null) {
notFound()
return
}
if (accountInstance.hasErrors()) {
respond accountInstance.errors, view:'edit'
return
}
accountInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'Account.label', default: 'Account'), accountInstance.id])
redirect accountInstance
}
'*'{ respond accountInstance, [status: OK] }
}
}
#Transactional
def delete(Account accountInstance) {
if (accountInstance == null) {
notFound()
return
}
accountInstance.delete flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'Account.label', default: 'Account'), accountInstance.id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'account.label', default: 'Account'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
{accountInstanceList} is not in the index action in the controller, where is it defined? Is there hidden class that is also generated?

The render method figures out the type of 'thing' you're trying to pass to the view and creates a suitable name, in the case of a list of domain objects it's DomainNameInstanceList, see the class DefaultHtmlRenderer
Also see the scaffollding section of the docs
...the standard scaffold views expect model variables of the form
<propertyName>InstanceList for collections and <propertyName>Instance
for single instances

Related

Create form for domain object with multiselect Enum field fails with 'Property xxx is type-mismatched'

I am using Grails 4.0.4 w/ GORM 7.0.7.RELEASE
The database I am using is MongoDB
I can successfully run the application and navigate to the create form for the domain class. I can select the value for the singleton field someOtherEnum. I can multiselect values for the categories field. When I submit the form, however, I get this message: 'Property categories is type-mismatched'. I used this approach based on the answers to another question posted here, but it's not working for me. I am not using an embedded enum or hasMany collection like that user.
The controller and service were generated by the generate-all command.
How to add a multiple enum field to the create and edit forms in Grails 4?
I have an enum located in src/main/groovy/com/project/core/dsl I am using to populate a multiselect field for a domain class:
package com.project.core.dsl
import groovy.transform.CompileStatic
#CompileStatic
enum Category {
CATEGORY_ONE("Category One"),
CATEGORY_TWO("Category Two"),
CATEGORY_THREE("Category Three")
private final String id
private Category(String id) { this.id = id }
#Override
String toString() { id }
String getKey() { name() }
}
The domain class:
package com.project.core
import com.project.core.dsl.SomeOtherEnum
import com.project.core.dsl.Category
class DomainObject {
SomeOtherEnum someOtherEnum
Set<Category> categories
static constraints = {
}
static mapping = {
someOtherEnum index: true
}
#Override
String toString() {
return "DomainObject{" +
"someOtherEnum=" + someOtherEnum +
", categories=" + categories +
'}';
}
}
In the create.gsp view, I have this form:
<g:form resource="${this.domainObject}" method="POST">
<fieldset class="form">
<f:with bean="domainObject">
<f:field property="someOtherEnum"/>
<f:field property="categories">
<g:select
multiple="true"
name="${property}"
from="${Category}"
value="${domainObject?.categories}"
/>
</f:field>
</f:with>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
The domain class Controller:
package com.project.core
import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
class DomainObject {
DomainObjectService domainObjectService
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond domainObjectService.list(params), model:[domainObjectCount: domainObjectService.count()]
}
def show(Long id) {
respond domainObjectService.get(id)
}
def create() {
respond new DomainObject(params)
}
def save(DomainObject domainObject) {
if (domainObject == null) {
notFound()
return
}
try {
domainObjectService.save(domainObject)
} catch (ValidationException e) {
respond domainObject.errors, view:'create'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), domainObject.id])
redirect domainObject
}
'*' { respond domainObject, [status: CREATED] }
}
}
def edit(Long id) {
respond domainObjectService.get(id)
}
def update(DomainObject domainObject) {
if (domainObject == null) {
notFound()
return
}
try {
domainObjectService.save(domainObject)
} catch (ValidationException e) {
respond domainObject.errors, view:'edit'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), domainObject.id])
redirect domainObject
}
'*'{ respond domainObject, [status: OK] }
}
}
def delete(Long id) {
if (id == null) {
notFound()
return
}
domainObjectService.delete(id)
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
The domain object service:
package com.project.core
import grails.gorm.services.Service
#Service(DomainObject)
interface DomainObjectService {
DomainObject get(Serializable id)
List<DomainObject> list(Map args)
Long count()
void delete(Serializable id)
DomainObject save(DomainObject domainObject)
}
I was able to get past my error by making the following changes. I added a hasMany statement in DomainObject
static hasMany = [categories: Category]
and I made these changes in the create.gsp file:
<f:field property="categories">
<g:select
multiple="true"
name="${property}"
from="${Category?.values()}"
optionKey="key"
value="${domainObject?.categories}"
/>
</f:field>

error appears when i add anything in my controller

i'm using Grails 2.5.1 on Windows 7 64 bit , After generating the controllers and the views using Grails command
generate-all "*"
When i add any new lines in my controllers i get the below error :
Compilation error: startup failed:
E:\Development\eclipse\TekDays\grails- app\controllers\com\tekdays\TekEventController.groovy:47: Ambiguous expression could be a parameterless closure expression, an isolated open code block, or it may continue a previous statement;solution: Add an explicit parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...}, and also either remove the previous newline, or add an explicit semicolon ';' # line 47, column 4.
{
^
1 error
here is my controller :
package com.tekdays
import static org.springframework.http.HttpStatus.*
#Transactional(readOnly = true)
class TekEventController
{
def taskService // this what i added
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max)
{
params.max = Math.min(max ?: 10, 100)
respond TekEvent.list(params), model:[tekEventInstanceCount: TekEvent.count()]
}
def show(TekEvent tekEventInstance)
{
respond tekEventInstance
}
def create()
{
respond new TekEvent(params)
}
#Transactional
def save(TekEvent tekEventInstance)
{
if (tekEventInstance == null)
{
notFound()
return
}
if (tekEventInstance.hasErrors())
{
respond tekEventInstance.errors, view:'create'
return
}
tekEventInstance.save flush:true
taskService.addDefaultTasks(tekEventInstance) // this what i added
request.withFormat
{
form multipartForm
{
flash.message = message(code: 'default.created.message', args: [message(code: 'tekEvent.label', default: 'TekEvent'), tekEventInstance.id])
redirect tekEventInstance
}
'*' { respond tekEventInstance, [status: CREATED] }
}
}
def edit(TekEvent tekEventInstance)
{
respond tekEventInstance
}
#Transactional
def update(TekEvent tekEventInstance)
{
if (tekEventInstance == null)
{
notFound()
return
}
if (tekEventInstance.hasErrors())
{
respond tekEventInstance.errors, view:'edit'
return
}
tekEventInstance.save flush:true
request.withFormat
{
form multipartForm
{
flash.message = message(code: 'default.updated.message', args: [message(code: 'TekEvent.label', default: 'TekEvent'), tekEventInstance.id])
redirect tekEventInstance
}
'*'
{
respond tekEventInstance, [status: OK]
}
}
}
#Transactional
def delete(TekEvent tekEventInstance)
{
if (tekEventInstance == null)
{
notFound()
return
}
tekEventInstance.delete flush:true
request.withFormat
{
form multipartForm
{
flash.message = message(code: 'default.deleted.message', args: [message(code: 'TekEvent.label', default: 'TekEvent'), tekEventInstance.id])
redirect action:"index", method:"GET"
}
'*'
{
render status: NO_CONTENT
}
}
}
protected void notFound()
{
request.withFormat
{
form multipartForm
{
flash.message = message(code: 'default.not.found.message', args: [message(code: 'tekEvent.label', default: 'TekEvent'), params.id])
redirect action: "index", method: "GET"
}
'*'
{
render status: NOT_FOUND
}
}
}
}
Any advice to solve this error ?
Thanks

Grails Static Mapping argument type mismatch when saving

I can make a simple grails app in 2.4.4, but as soon as I add in static mapping that changes the name of the primary key it refuses to save. Here is the domain class I use.
class Liaison {
String first;
String last;
static constraints = {}
static mapping = {
id column:'liaisonId', type: 'integer'
}
}
here is the generated controller
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
#Transactional(readOnly = true)
class LiaisonController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Liaison.list(params), model:[liaisonInstanceCount: Liaison.count()]
}
def show(Liaison liaisonInstance) {
respond liaisonInstance
}
def create() {
respond new Liaison(params)
}
#Transactional
def save(Liaison liaisonInstance) {
if (liaisonInstance == null) {
notFound()
return
}
if (liaisonInstance.hasErrors()) {
respond liaisonInstance.errors, view:'create'
return
}
liaisonInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'liaison.label', default: 'Liaison'), liaisonInstance.id])
redirect liaisonInstance
}
'*' { respond liaisonInstance, [status: CREATED] }
}
}
def edit(Liaison liaisonInstance) {
respond liaisonInstance
}
#Transactional
def update(Liaison liaisonInstance) {
if (liaisonInstance == null) {
notFound()
return
}
if (liaisonInstance.hasErrors()) {
respond liaisonInstance.errors, view:'edit'
return
}
liaisonInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'Liaison.label', default: 'Liaison'), liaisonInstance.id])
redirect liaisonInstance
}
'*'{ respond liaisonInstance, [status: OK] }
}
}
#Transactional
def delete(Liaison liaisonInstance) {
if (liaisonInstance == null) {
notFound()
return
}
liaisonInstance.delete flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'Liaison.label', default: 'Liaison'), liaisonInstance.id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'liaison.label', default: 'Liaison'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
I get an error at liaisonInstance.save flush:true in the def save(), but I don't understand why. If I look in my change log the table looks to be fine. Is it some sort of hidden hash map? Any help would be great.
Omg I think I get it. I was over-thinking. The static mapping should be
static mapping = {
id column: 'liaisonId'
}
instead of
static mapping = {
id column: 'liaisonId', type: 'integer'
}
I think it has to do with the auto generated primary key is a bigInt. I think type is only for if you plan on using an id generator for primary key.

Grails controller's beforeInterceptor

I am trying to make it so that no matter what function of my controller is accessed, if the session has been nulled, it goes back to the log in page after you click ok on a modal that pops up saying the session has expired but I can't quite get it to work. Here are the first few methods of this controller:
def beforeInterceptor = {
[action:this.&checkSession()]
}
def checkSession() {
if (!session.user) {
render text: """<script type="text/javascript"> alert('Session expired. Please log in again.'); window.location.href = data.url;</script>""",
contentType: 'js'
}
}
def index() {
redirect (action: customerLogin)
}
def customerLogin = {
selectedBatch = null
}
def authenticate = {
def user = null
def possibleUsersList = User.findAllWhere(user_name: params.username)
possibleUsersList.each {
if (bcryptService.checkPassword(params.password, it.user_password))
user = it
}
if (user) {
session.user = user
greetingName = user.user_name
render(contentType: 'text/json') {
[success: true, url: createLink(controller: 'customer', action: 'custMainPage')]
}
}
else {
//def messages = ResourceBundle.getBundle('messages')
//def errorstring = bundle.getString("fatcaone.login.error")
//println "Login error: " + ${errorstring}
render (contentType: 'text/json') {
//["message": '<p>code=fatcaone.login.error</p>']
["message": '<p>Login or Password incorrect.</p>']
}
}
}
def logout = {
if (session.user != null) {
flash.message = "Goodbye ${session.user.fullName}"
session.user = null
}
redirect(action: customerLogin)
}
beforeInterceptor has been removed from Grails 3.0.
See https://github.com/grails/grails-core/issues/635 for a discussion of this.
Given that you want to keep your code as it is do:
def beforeInterceptor = {
[action:this.&checkSession()]
}
private def checkSession() {
if (!session.user) {
flash.error = 'Session expired. Please log in again.'
redirect(action: customerLogin)
return false
}
}
def index() {
redirect (action: customerLogin)
}
def customerLogin = {
selectedBatch = null
}
def authenticate = {
def user = null
def possibleUsersList = User.findAllWhere(user_name: params.username)
possibleUsersList.each {
if (bcryptService.checkPassword(params.password, it.user_password))
user = it
}
if (user) {
session.user = user
greetingName = user.user_name
render(contentType: 'text/json') {
[success: true, url: createLink(controller: 'customer', action: 'custMainPage')]
}
}
else {
//def messages = ResourceBundle.getBundle('messages')
//def errorstring = bundle.getString("fatcaone.login.error")
//println "Login error: " + ${errorstring}
render (contentType: 'text/json') {
//["message": '<p>code=fatcaone.login.error</p>']
["message": '<p>Login or Password incorrect.</p>']
}
}
}
def logout = {
if (session.user != null) {
flash.message = "Goodbye ${session.user.fullName}"
session.user = null
}
redirect(action: customerLogin)
}
And in your login page add:
<g:if test="${flash.error}">
<script type="text/javascript">
alert('${flash.error}');
</script>
</g:if>
Check this
def checkSession() {
if (session == null || session["loginId"] == null) {
render text: """<script type="text/javascript"> alert('Session expired. Please log in again.'); window.location.href = "${createLink(controller: 'test',action: 'logout')}";</script>""",
contentType: 'js';
return false;
}
}

Enum constructor calls ara only allowed inside the enum class

I'm working on a grails project. Right now I have a very disturbing problem. I have an enum called Status like this:
enum Status {
ENABLED("Habilitado"), DISABLED ("Desabilitado")
String type
private Status(String type) {
this.type = type
}
def String toString() {
return this.type
}
static list() {
[ENABLED, DISABLED]
}
}
I also have a controller called TesterController, which is where I keep getting errors saying "Enum constructor calls are only allowed inside the enum class" The thing is: I do not call the enum constructor from inside the controller class! Here it is:
class TesterController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index() {
redirect(action: "list", params: params)
}
def list() {
def minElems = 10
if(params.max) minElems = params.int('max')
params.max = Math.min(minElems, 100)
[testers: Tester.list(params), testerTotal: Tester.count()]
}
def create() {
[tester: new Tester(params)]
}
def save() {
def tester = new Tester(params)
if (!tester.save(flush: true)) {
render(view: "create", model: [tester: tester])
return
}
flash.message = message(code: 'ateweb.created.message', args: [tester.name])
redirect(action: "show", id: tester.id)
}
def show() {
def tester = Tester.get(params.id)
if (!tester) {
flash.message = message(code: 'ateweb.not.found.message', args: [message(code: 'tester.label', default: 'Tester'), params.name])
redirect(action: "list")
return
}
[tester: tester]
}
def edit() {
def tester = Tester.get(params.id)
if (!tester) {
flash.message = message(code: 'ateweb.not.found.message', args: [message(code: 'tester.label', default: 'Tester'), params.name])
redirect(action: "list")
return
}
[tester: tester]
}
def update() {
def tester = Tester.get(params.id)
if (!tester) {
flash.message = message(code: 'ateweb.not.found.message', args: [message(code: 'tester.label', default: 'Tester'), params.name])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (tester.version > version) {
tester.errors.rejectValue("version", "ateweb.optimistic.locking.failure",
[message(code: 'tester.label', default: 'Tester')] as Object[],
"Another user has updated this Tester while you were editing")
render(view: "edit", model: [tester: tester])
return
}
}
tester.properties = params
if (!tester.save(flush: true)) {
render(view: "edit", model: [tester: tester])
return
}
flash.message = message(code: 'ateweb.updated.message', args: [tester.name])
redirect(action: "show", id: tester.id)
}
}
Ok. So I am lost with this. Any help is appreciated.
There are a few issues with the definition of your Status class, though I don't know if these are the cause of your problem
enum Status {
ENABLED("Habilitado"), DISABLED ("Desabilitado")
String type
// delcaring the constructor private doesn't make much sense because
// enum constuctors can never be called outside the class
private Status(String type) {
this.type = type
}
// return type is declared as both def (Object) and String
def String toString() {
return this.type
}
// this is identical to the automatically-generated values() method
static list() {
[ENABLED, DISABLED]
}
}
Redefine this class as
enum Status {
ENABLED("Habilitado"), DISABLED ("Desabilitado")
String type
Status(String type) {
this.type = type
}
String toString() {
return this.type
}
}
and use values() instead of the deleted list() method, and maybe your problem will disappear

Resources