Reputation: 725
i have a class User in my WebApplication and a class Driver, which is a subclass of User. Here is the code:
package elektrova
class User {
String username
String password
String firstName
String lastName
UserRole role
static belongsTo = [
hauler:Hauler
]
static hasMany = [
createdJobs:Job,
activities:UserActivityHistory
]
static mappedBy = [
createdJobs:'creationUser'
]
static mapping = { tablePerHierarchy false }
static constraints = {
username(blank:false, size:4..15,matches:/[\S]+/, unique:true)
password(blank:false, size:4..15,matches:/[\S]+/)
firstName(blank:false, nullable:false)
lastName(blank:false, nullable:false)
role(blank:false, nullable:false)
}
@Override
def encodeAsHTML(){
firstName + " " + lastName
}
}
class Driver extends User{
UserRole role = UserRole.DRIVER
static hasMany = [
assignedJobs:Job
]
static mappedBy = [assignedJobs:'assignedUser']
static constraints = {
}
}
Here is the creation of the tesdata in the bootstrap:
User dispo = new Driver(hauler: hauler, firstName: "Dis", lastName: "Po", password: "dispo", role: UserRole.ADMIN, username: "dispo" ).save(failOnError: true)
Driver driver = new Driver(hauler: hauler, firstName: "Kai", lastName: "Uwe", password: "kauw", role: UserRole.DRIVER, username: "kauw" ).save(failOnError: true)
Driver driver2 = new Driver(hauler: hauler, firstName: "Hans", lastName: "Juergen", password: "haju", role: UserRole.DRIVER, username: "haju" ).save(failOnError: true)
User admin = new User(hauler: hauler, firstName: "Ad", lastName: "Min", password: "admin", role: UserRole.ADMIN, username: "admin" ).save(failOnError: true)
User admin2 = new User(hauler: hauler, firstName: "Ad", lastName: "Min", password: "admin", role: UserRole.ADMIN, username: "admin2" ).save(failOnError: true)
And the show.gsp:
<%@ page import="elektrova.User"%>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName"
value="${message(code: 'user.label', default: 'User')}" />
<title><g:message code="default.show.label" args="[entityName]" /></title>
</head>
<body>
<g:render template="/navi/navbar" />
<a href="#show-user" class="skip" tabindex="-1"><g:message
code="default.link.skip.label" default="Skip to content…" /></a>
<div class="nav" role="navigation">
<ul>
<li><g:link class="list" action="index">
<g:message code="view.user.button.label.list" args="[entityName]" />
</g:link></li>
<li><g:link class="create" action="create">
<g:message code="view.user.button.label.create" args="[entityName]" />
</g:link></li>
</ul>
</div>
<div id="show-user" class="scaffold-show" role="main">
<h1>
<g:message code="default.show.label" args="[entityName]" />${userInstance.toString() }
</h1>
<g:if test="${flash.message}">
<div class="message" role="status">
${flash.message}
</div>
</g:if>
<ol class="property-list user">
<% System.out.println "user : " + userInstance %>
<g:if test="${userInstance?.hauler}">
<li class="fieldcontain"><span id="hauler-label"
class="property-label"><g:message code="hauler.label"
default="Hauler" /></span> <span class="property-value"
aria-labelledby="hauler-label"><g:link controller="hauler"
action="show" id="${userInstance?.hauler?.id}">
${userInstance?.hauler?.encodeAsHTML()}
</g:link></span></li>
</g:if>
<g:if test="${userInstance?.username}">
<li class="fieldcontain"><span id="username-label"
class="property-label"><g:message code="user.username.label"
default="Username" /></span> <span class="property-value"
aria-labelledby="username-label"><g:fieldValue
bean="${userInstance}" field="username" /></span></li>
</g:if>
<g:if test="${userInstance?.password}">
<li class="fieldcontain"><span id="password-label"
class="property-label"><g:message code="user.password.label"
default="Password" /></span> <span class="property-value"
aria-labelledby="password-label"><g:fieldValue
bean="${userInstance}" field="password" /></span></li>
</g:if>
<g:if test="${userInstance?.firstName}">
<li class="fieldcontain"><span id="firstName-label"
class="property-label"><g:message
code="user.firstName.label" default="First Name" /></span> <span
class="property-value" aria-labelledby="firstName-label"><g:fieldValue
bean="${userInstance}" field="firstName" /></span></li>
</g:if>
<g:if test="${userInstance?.lastName}">
<li class="fieldcontain"><span id="lastName-label"
class="property-label"><g:message code="user.lastName.label"
default="Last Name" /></span> <span class="property-value"
aria-labelledby="lastName-label"><g:fieldValue
bean="${userInstance}" field="lastName" /></span></li>
</g:if>
<g:if test="${userInstance?.role}">
<li class="fieldcontain"><span id="role-label"
class="property-label"><g:message code="user.role.label"
default="Role" /></span> <span class="property-value"
aria-labelledby="role-label"><g:fieldValue
bean="${userInstance}" field="role" /></span></li>
</g:if>
<g:if test="${userInstance?.createdJobs}">
<li class="fieldcontain"><span id="createdJobs-label"
class="property-label"><g:message
code="user.createdJobs.label" default="Created Jobs" /></span> <g:each
in="${userInstance.createdJobs}" var="c">
<span class="property-value" aria-labelledby="createdJobs-label"><g:link
controller="job" action="show" id="${c.id}">
${c?.encodeAsHTML()}
</g:link></span>
</g:each></li>
</g:if>
<g:if test="${userInstance?.createdJobs}">
<li class="fieldcontain"><span id="createdJobs-label"
class="property-label"><g:message
code="user.createdJobs.label" default="Created Jobs" /></span> <g:each
in="${userInstance.createdJobs}" var="c">
<span class="property-value" aria-labelledby="createdJobs-label"><g:link
controller="job" action="show" id="${c.id}">
${c?.encodeAsHTML()}
</g:link></span>
</g:each></li>
</g:if>
</ol>
<g:form url="[resource:userInstance, action:'delete']" method="DELETE">
<fieldset class="buttons">
<g:link class="edit" action="edit" resource="${userInstance}">
<g:message code="default.button.edit.label" default="Edit" />
</g:link>
<g:actionSubmit class="delete" action="delete"
value="${message(code: 'default.button.delete.label', default: 'Delete')}"
onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form>
</div>
And the controller:
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
@Transactional(readOnly = true)
class UserController {
def beforeInterceptor = [action: this.&auth]
def auth = {
if(!session.user) {
redirect(controller:"login", action: "index")
}
}
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
boolean isAdmin
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
model:[userInstanceList: User.list(params),userInstanceCount: User.count()]
}
def show(User userInstance) {
println 'User: ' + userInstance
respond userInstance
}
def create() {
respond new User(params)
}
@Transactional
def save(User userInstance) {
if (userInstance == null) {
notFound()
return
}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'create'
return
}
userInstance.save flush:true
request.withFormat {
form {
flash.message = message(code: 'default.created.message', args: [message(code: 'userInstance.label', default: 'User'), userInstance.id])
redirect userInstance
}
'*' { respond userInstance, [status: CREATED] }
}
}
def edit(User userInstance) {
respond userInstance
}
@Transactional
def update(User userInstance) {
if (userInstance == null) {
notFound()
return
}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'edit'
return
}
userInstance.save flush:true
request.withFormat {
form {
flash.message = message(code: 'default.updated.message', args: [message(code: 'User.label', default: 'User'), userInstance.id])
redirect userInstance
}
'*'{ respond userInstance, [status: OK] }
}
}
@Transactional
def delete(User userInstance) {
if (userInstance == null) {
notFound()
return
}
userInstance.delete flush:true
request.withFormat {
form {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'User.label', default: 'User'), userInstance.id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'userInstance.label', default: 'User'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
Now everything works fine in the UserController, the right User instance is always passed to the view. But the gsp receives null for all objects, except for the two admins, they are rendered correctly. At first I thought its because the view cant handle subclasses, but the Dispo User is also not shown. Changing the role of the other instances still wont display them. Any suggestions what to do?
Upvotes: 3
Views: 1646
Reputation: 8323
It's an old question but I just ran into the same problem and "fixed" it by adding a model argument to the respond
statement:
def show(User userInstance) {
println 'User: ' + userInstance
respond userInstance, model:[userInstance:userInstance]
}
In my case, the "User" class is a base class while I'm actually dealing with its inherited classes in the base class controller. respond
is completely confused by that.
Upvotes: 3