I have a domain class TmMessage for which I use generate-all to create the scaffolded controller and views. The auto-generated show() method looks like:
def show(TmMessage tmMessage) {
respond tmMessage
}
Scaffolding is defined in my BuildConfig.groovy:
plugins {
compile ":scaffolding:2.1.2"
}
The list of TmMessage objects is given by controller's method:
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond TmMessage.list(params), model:[tmMessageCount: TmMessage.count()]
}
The TmMessages are stored in a hasMany List of a parent object, TmBulkMessage, and I can see the TmMessages listed ok in when inspecting a TmBulkMessage. However, the list of TmMessage objects displays nothing (I can see a number of pages of TmMessage objects, but the details for them don't display). When I click on one of the links from the TmBulkMessage to look at a specific TmMessage object, nothing displays. I believe that's because the tmMessage being displayed is null.
The show() method is very different to what I've seen elsewhere, where it looks like (taken straight from Grails docs):
def show() {
def book = Book.get(params.id)
log.error(book)
[bookInstance : book]
}
The auto-generated unit tests all use the first method, so what's going on here please? Is there something missing from the scaffolded code?
EDIT:
From the Grails docs, what's new in 2.3 (I'm using 2.4):
Domain Classes As Command Objects When a domain class is used as a command object and there is an id request parameter, the framework will retrieve the instance of the domain class from the database using the id request parameter.
So it would appear that the domain class / command object interface provided by Grails is returning null.
FURTHER EDIT:
Thanks to Gregor's help, it would appear that the domain object binding is working ok, but that the respond isn't working as advertised.
The show.gsp is below:
<%@ page import="com.example.TmMessage" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'tmMessage.label', default: 'TmMessage')}" />
<title><g:message code="default.show.label" args="[entityName]" /></title>
</head>
<body>
<a href="#show-tmMessage" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content…"/></a>
<div class="nav" role="navigation">
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="list" action="index"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="show-tmMessage" class="content scaffold-show" role="main">
<h1><g:message code="default.show.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<ol class="property-list tmMessage">
<g:if test="${tmMessage?.bulkMessage}">
<li class="fieldcontain">
<span id="bulkMessage-label" class="property-label"><g:message code="tmMessage.bulkMessage.label" default="Bulk Message" /></span>
<span class="property-value" aria-labelledby="bulkMessage-label"><g:link controller="tmBulkMessage" action="show" id="${tmMessage?.bulkMessage?.id}">${tmMessage?.bulkMessage?.encodeAsHTML()}</g:link></span>
</li>
</g:if>
<g:if test="${tmMessage?.message}">
<li class="fieldcontain">
<span id="message-label" class="property-label"><g:message code="tmMessage.message.label" default="Message" /></span>
<span class="property-value" aria-labelledby="message-label"><g:fieldValue bean="${tmMessage}" field="message"/></span>
</li>
</g:if>
</ol>
<g:form url="[resource:tmMessage, action:'delete']" method="DELETE">
<fieldset class="buttons">
<g:link class="edit" action="edit" resource="${tmMessage}"><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>
</body>
</html>
The output of tmMessage?.dump() within show() is:
<com.example.TmMessage@6d6cf0a5 message=abc errors=grails.validation.ValidationErrors: 0 errors $changedProperties=null id=1 version=0 bulkMessage=com.example.TmBulkMessage : 1>
If I amend the gsp to read:
<ol class="property-list tmMessage">
<% System.out.println "tmMessage : " + tmMessage %>
Then I get "tmMessage : null" written to the console when I view the page.
I have changed show() to read:
def show(TmMessage tmMessage) {
respond tmMessage, [model: [tmMessage : tmMessage]]
}
Which appears to fix the rendering issue for show. I don't know what needs to be changed for index(). When I select "edit" from the show page, I get a blank textfield for the message field and I don't know if this is expected behaviour or not, but it would be much preferred if the field was preloaded with the existing value.
show
links and add aformat=json
GET parameter to it? Did you add the controller explicitly toUrlMappings
? If you put aprintln
inside yourshow
method, does it output anything? – Gregor Petrinshow.gsp
in the proper folder (e.g.views/tmMessage/show.gsp
)? – Gregor Petrinprintln tmMessage?.dump()
into theshow
action? – Gregor Petrin