首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Grails为什么响应不起作用,什么也不呈现?

Grails为什么响应不起作用,什么也不呈现?
EN

Stack Overflow用户
提问于 2014-12-02 11:37:16
回答 3查看 3.4K关注 0票数 1

我有一个域类TmMessage,我使用generate-all来创建脚手架控制器和视图。自动生成的show()方法如下所示:

代码语言:javascript
复制
def show(TmMessage tmMessage) {
    respond tmMessage
}

脚手架在我的BuildConfig.groovy中定义:

代码语言:javascript
复制
plugins {
    compile ":scaffolding:2.1.2"
}

TmMessage对象的列表是通过控制器的方法给出的:

代码语言:javascript
复制
def index(Integer max) {
    params.max = Math.min(max ?: 10, 100)
    respond TmMessage.list(params), model:[tmMessageCount: TmMessage.count()]
}

TmMessages存储在父对象TmBulkMessage的hasMany列表中,我可以在检查TmBulkMessage时看到列出的TmMessages。但是,TmMessage对象列表没有显示任何内容(我可以看到许多TmMessage对象的页面,但它们的详细信息没有显示)。当我单击TmBulkMessage中的一个链接来查看特定的TmMessage对象时,什么都不会显示。我相信这是因为正在显示的tmMessage是空的。

show()方法与我在其他地方看到的非常不同,在那里它看起来很像(直接取自Grails docs):

代码语言:javascript
复制
def show() {
    def book = Book.get(params.id)
    log.error(book)
    [bookInstance : book]
}

自动生成的单元测试都使用第一种方法,所以这里发生了什么?脚手架代码中有没有遗漏什么?

编辑:

在Grails文档中,什么是2.3中的新内容(我使用2.4):

域类作为命令对象当域类被用作命令对象并且有id请求参数时,框架将使用id请求参数从数据库中检索域类的实例。

因此,看来Grails提供的域类/命令对象接口正在返回null。

进一步编辑:

感谢Gregor的帮助,似乎域对象绑定工作正常,但响应不像广告中所显示的那样有效。

show.gsp如下:

代码语言:javascript
复制
<%@ 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&hellip;"/></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>

tmMessage?.dump()在show()中的输出是:

代码语言:javascript
复制
<com.example.TmMessage@6d6cf0a5 message=abc errors=grails.validation.ValidationErrors: 0 errors $changedProperties=null id=1 version=0 bulkMessage=com.example.TmBulkMessage : 1>

如果我将普惠制修正为:

代码语言:javascript
复制
<ol class="property-list tmMessage">
    <% System.out.println "tmMessage : " + tmMessage %>

然后在查看页面时将"tmMessage : null“写入控制台。

我把show()改为:

代码语言:javascript
复制
def show(TmMessage tmMessage) {
    respond tmMessage, [model: [tmMessage : tmMessage]]
}

它似乎修复了显示的呈现问题。我不知道索引()需要更改什么。当我从显示页面中选择“编辑”时,我会得到消息字段的一个空白文本字段,我不知道这是否是预期的行为,但是如果该字段预先加载了现有的值,则会更好。

EN

回答 3

Stack Overflow用户

发布于 2014-12-02 20:34:54

我想我现在知道了问题所在:respond有一个非常奇怪的变量命名约定。如果您使用单个TmMessage实例进行响应,则该变量将在视图中被称为tmMessageInstance。如果您使用它们的列表进行响应,则该变量将被称为tmMessageInstanceList。如果你还一套..。你知道我的意思。

因此,在上面的GSP代码中,您可能可以将所有tmMessage替换为tmMessageInstance,并去掉控制器中的[model: [tmMessage : tmMessage]]。我的一个习惯是在我编写的每一个GSP中显式地测试每个预期模型变量的存在和类型,比如:<% assert tmModelInstance instanceof com.package.TmModel %>。然后,这些行充当文档,如果控制器将一些意外的内容传递到GSP中(在活动开发期间,特别是在从服务填充数据模型时),您的代码显然会出现一个很好的诊断消息。

在我看来,Grails的一个更好的选择是坚持respond呈现器的单个变量(例如,model),将其记录在几个地方,这样就没有人会错过它,然后人们就可以在必要时检测到其中的内容(不管怎么说,这种情况发生的频率是多少次,而您不知道是否会有一个列表或单个视图/模板的实例?)

编辑:显然,您可以在respond中使用Map语法,并将它用作获取固定变量名称的模型,只是文档很少:https://github.com/grails/grails-doc/commit/13cacbdce73ca431619362634321ba5f0be570a1

票数 8
EN

Stack Overflow用户

发布于 2014-12-02 14:27:32

感谢Gregor,他的帮助使我走上了正确的轨道,问题在于生成的代码。似乎没有一个模型被传递给视图,因此它没有渲染任何东西。下面是对index()的更改,显示()编辑()

代码语言:javascript
复制
def index(Integer max) {
    params.max = Math.min(max ?: 10, 100)
    respond TmMessage.list(params), model:[tmMessageCount: TmMessage.count(), tmMessageList : TmMessage.list(params)]
}


def show(TmMessage tmMessage) {
    respond tmMessage, [model: [tmMessage: tmMessage]]
}

def edit(TmMessage tmMessage) {
    respond tmMessage, [model: [tmMessage: tmMessage]]
}

这将使用正确的值预加载文本字段。

我还必须修改在创建时出现错误时发送的参数,将模型与所需的视图一起传递。下面是保存()的示例:

代码语言:javascript
复制
@Transactional
def save(TmMessage tmMessage) {
    if (tmMessage == null) {
        notFound()
        return
    }

    if (tmMessage.hasErrors()) {
        respond tmMessage.errors, [view:'create', model: [tmMessage: tmMessage]] 
        return
    }

    tmMessage.save flush:true

    request.withFormat {
        form multipartForm {
            flash.message = message(code: 'default.created.message', args: [message(code: 'tmMessage.label', default: 'TmMessage'), tmMessage.id])
            redirect tmMessage
        }
        '*' { respond tmMessage, [status: CREATED] }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2016-09-06 15:07:44

当我拥有域模型中的继承时,这种情况就发生了。

例如,如果我们有

代码语言:javascript
复制
class Vehicle {}

代码语言:javascript
复制
class Car extends Vehicle {}

当视图试图呈现carInstanceList时,脚手架控制器操作将vehicleInstanceList.传递到视图中。

正如前面的答案所述,响应方法按约定创建变量名,该约定在这里似乎失败了。

代码语言:javascript
复制
def index(Integer max) {
  params.max = Math.min(max ?: 10, 100)
  respond Vehicle.list(params), model:[vehicleInstanceCount: Vehicle.count()] //actually injecting carInstanceList
}

必须改为:

代码语言:javascript
复制
def index(Integer max) {
  params.max = Math.min(max ?: 10, 100)
  def vehicles = Vehicle.list(params)
  respond vehicles, model:[vehicleInstanceCount: Vehicle.count(), vehicleInstanceList:vehicles]
}

我认为这与检查列表中第一个元素的类有关,如果这是一辆汽车,将其命名为carInstanceList,如果第一个是车辆,那么这个问题可能不会出现。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27248477

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档