chelder
chelder

Reputation: 3987

How to use transients domain attributes with Grails Fields Plugin

I'm trying to add the field confirm password to an user register form. This is an extract of my domain class:

package usuario

class Usuario {

    transient springSecurityService

    String password
    String confirmarPassword

    static constraints = {

        password blank: false, password: true, size:5..15, matches:/[\S]+/
        confirmarPassword blank:false, password: true, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
            if (obj.password != obj.confirmarPassword)
                return 'usuario.password.dontmatch'
        }

    }   

    static transients = ['confirmarPassword']

    static mapping = {
        password column: '`password`'
    }

    Set<Rol> getAuthorities() {
        UsuarioRol.findAllByUsuario(this).collect { it.rol } as Set
    }

    def beforeInsert() {
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
        }
    }

    protected void encodePassword() {
        password = springSecurityService.encodePassword(password)
    }
}

obj.confirmarPassword is always null so the constraint is never accomplished.

I installed the Grails Templates as it is suggested here. I changed the attribute persistentProperties, but it is only at _form.gsp, and _form.gsp is not used by Grails Fields Plugins. Therefore, the transients attributes don't appear in the Internet Browser.

I copied the generated transients attributes of the _form.gsp to create.gsp:

<fieldset>
    <g:form class="form-horizontal" action="create" >

        <div class="fieldcontain ${hasErrors(bean: usuarioInstance, field: 'confirmarPassword', 'error')} required">
            <label for="confirmarPassword">
                <g:message code="usuario.confirmarPassword.label" default="Confirmar Password" />
                <span class="required-indicator">*</span>
            </label>
            <g:field type="password" name="confirmarPassword" maxlength="15" pattern="${usuarioInstance.constraints.confirmarPassword.matches}" required="" value="${usuarioInstance?.confirmarPassword}"/>
        </div>

        <fieldset>          
            <f:all bean="usuarioInstance"/>
            <div class="form-actions">
                <button type="submit" class="btn btn-primary">
                    <i class="icon-ok icon-white"></i>
                    <g:message code="default.button.create.label" default="Create" />
                </button>
            </div>
        </fieldset>
    </g:form>
</fieldset>

The transients attributes appear on the screen, but obj.confirmarPassword is still null

The last approach I thought is to modify views_fields\default_field.gsp to also use these transients attributes, but I didn't find how. This is the documentation. This is the content of that file:

<%@ page defaultCodec="html" %>
<div class="control-group ${invalid ? 'error' : ''}">
    <label class="control-label" for="${property}">${label}</label>
    <div class="controls">
        <%= widget %>
        <g:if test="${invalid}"><span class="help-inline">${errors.join('<br>')}</span></g:if>
    </div>
</div>

Is it possible with Grails Fields Plugin? Where are the conditions tested, on client or server side? (I think part of the checking is on client side, but all the restrictions are checked again on server side).

Upvotes: 2

Views: 5262

Answers (2)

chelder
chelder

Reputation: 3987

In latest versions of Grails, transient attributes are not binded with form by default. This is the documentation of the bindable constraint. This is how my code would become (I just added bindable: true):

static constraints = {

    password blank: false, password: true, size:5..15, matches:/[\S]+/
    confirmarPassword bindable: true, blank:false, password: true, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
        if (obj.password != obj.confirmarPassword)
            return 'usuario.password.dontmatch'
    }
}

However, transient attributes are not shown with <f:all bean="usuarioInstance"/>, We have to add these attributes manually: <f:field bean="${usuarioInstance}" property="confirmarPassword" />. It is not an ideal solution. I'll keep this question open some days hoping that someone knows the answer.

UPDATE

In my case, the above solution didn't work either because I'm using Spring Security Core plugin. It gives the next error:

null id in usuario.Usuario entry (don't flush the Session after an exception occurs)

In that case, we have to use a command object. That issue is described (and solved) in this post.

Upvotes: 1

Daniel Wondyifraw
Daniel Wondyifraw

Reputation: 7713

Oh that i have i encountered it before .

Declaring

        String confirmarPassword

and making it traniset it doesn't work me like this

        static transients = ['confirmarPassword']

But

        transient  confirmarPassword 

As you did it for the springService...i don't now why that doesn't work and this , some one may have a better clarification ...

Upvotes: 1

Related Questions