Grails-ish通过不同网络上的电子邮件为用户建模的方法

时间:2014-06-24 11:35:14

标签: grails gorm

我所拥有的是一组用户和一组网络,这些用户需要在各种网络上拥有不同的电子邮件地址 - 一些是内部的,一些是外部的,一些是开发的,他们是所有人都有自己的命名和寻址方案。

到目前为止,我所做的是简化,删除了无关的代码:

class Network {

    String name

    static hasMany = [email: Email]

}

class User {

    String login

    static hasMany = [email: Email]

}

class Email {

    string address

    static belongsTo = [user: User, network: Network]

}

我正在苦苦挣扎,假设这是建立这种关系的正确方法,那就是如何解决给定用户和网络的电子邮件地址。例如,在用户创建页面中:

<g:each
    in="${com.damascusgrp.dto.Network.findAll()}">
    <div class="fieldcontain ${hasErrors(bean: userInstance, field: 'email', 'error')} required">
        <label for="email">
            ${it.name} 
            <span class="required-indicator">*</span>
        </label>
        <g:field type="email" name="email" required="" value="${userInstance?.email}"/>
    </div>
</g:each>

但我确定&#34;价值&#34;是不正确的,我只是无法绕过应有的东西。称之为Java阻止我在Groovy中正确思考。

或者,我完全错过了完全没有这种方法吗?我将此代码从单个电子邮件地址升级为User类的一部分,当我考虑制作一个居住在User中的HashMap时,我想先尝试一下。

- - - - - - - - 更新

我创建了一个空项目,只有上面列出的三个类,让Grails构建控制器&amp;让他们看到它会做什么。我从中修改过的内容如下所示:

<ul class="one-to-many">
    <g:each in="${userInstance?.email?}" var="e">
        <li><g:link controller="email" action="show" id="${e.id}">${e?.encodeAsHTML()}</g:link></li>
    </g:each>
    <li class="add">
        <g:link controller="email" action="create" params="['user.id': userInstance?.id]">${message(code: 'default.add.label', args: [message(code: 'email.label', default: 'Email')])}</g:link>
    </li>
</ul>

我基本上逐字逐句地从脚手架视图中将其折叠到我的代码中。我现在需要弄清楚如何隐藏&#34;来自电子邮件创建页面的用户字段,或者更好的是使用JQuery或类似的东西在一个页面上完成所有操作。或按照建议切换到地图。

------第二次更新-----

实例化是唯一剩下的问题。当我尝试实例化它并向其添加新的电子邮件时,我得到了一个N​​PE:

java.lang.NullPointerException: Cannot invoke method collectEntries() on null object
    at com.damascusgrp.dto.User.getEmailsByNetwork(User.groovy:37)
    at com.damascusgrp.dto.UserSpec.Fully constructed user is good(UserSpec.groovy:44)

我已经尝试了各种方法来预加载它,或者为每个已定义的网络设置空白条目,但还没有任何工作正常。这里是现在的代码,在Ian的帮助下。

class User {

    String login
    String password
    String firstName
    String lastName
    String filePath
    static hasMany = [requests:Request, email: Email]

    static transients = ['emailsByNetwork']  

    def User(String l) {
        login = l
    }

    def getName() {
        "${firstName} ${lastName}"
    }

    String toString() {
        login
    }

    static constraints = {
        login blank:false, size:5..15, matches:/[\S]+/, unique:true
        password blank:false, size:5..15, matches:/[\S]+/
        firstName blank:false
        lastName blank:false
        filePath blank:false 
    }

    Map getEmailsByNetwork() {
        email.collectEntries { [(it.network.id), it] }
    }

    def addToEmail(Email em) {
        email[em.network.id] = em 
    }

}

1 个答案:

答案 0 :(得分:1)

您的示例GSP表明,每个User的域模型都有Email只有一个Network - User不能有两个Email Network同一User上的对象。所以我要在class User { String login static hasMany = [email: Email] Map getEmailsByNetwork() { (email?.collectEntries { [it.network.id, it] }) ?: [:] } static transients = ['emailsByNetwork'] } 域类

中添加一个瞬态属性
user.emailsByNetwork

现在Network将是从Email ID到<g:set var="emailsByNet" value="${userInstance.emailsByNetwork}" /> <g:each var="net" in="${com.damascusgrp.dto.Network.findAll()}"> <div class="fieldcontain ${hasErrors(bean: emailsByNet[net.id], field: 'email', 'error')} required"> <label for="net_${net.id}_email"> ${net.name} <span class="required-indicator">*</span> </label> <g:field type="email" name="net_${net.id}_email" required="" value="${emailsByNet[net.id]?.email}"/> </div> </g:each> 的地图,在GSP中你可以说

params.net_1_email

在收到此表单帖子的控制器中,您必须相应地处理各种emailsByNetwork[n]等,如果存在则更新现有userInstance.addToEmail(new Email(network:Network.load(n), email:value))或如果不存在则更新{{1}}。