2012-10-22 10 views
5

Attualmente sto sviluppando un'applicazione Grails e sto lavorando con i plug-in Spring Security e UI. Ho creato il rapporto tra la classe utente e un altro Area Classe che ho che può essere visto qui sotto:Grails - salva l'istanza transitoria prima di svuotare i graal Errore?

User Class:

class User { 

    transient springSecurityService 

    String username 
    String email 
    String password 
    boolean enabled 
    boolean accountExpired 
    boolean accountLocked 
    boolean passwordExpired 

    static belongsTo = [area:Areas] 

     ....... 
} 

Area Classe:

class Areas { 

    String name 

    static hasMany = [users:User] 

} 

Come si può vedere dalle classi un utente può essere collegato a un'area, ma un'area potrebbe avere molti utenti. Funziona tutto bene e quando eseguo il bootstrap dell'applicazione tutti i dati vengono aggiunti correttamente. tuttavia ottengo il seguente errore quando provo ad utilizzare un modulo per creare un nuovo utente:

object references an unsaved transient instance - save the transient instance before flushing: com.website.Area 

sotto è il codice di controllo che sto usando per salvare le informazioni:

def save = {  
     def user = lookupUserClass().newInstance(params) 

     if (params.password) { 
      String salt = saltSource instanceof NullSaltSource ? null : params.username 
      user.password = springSecurityUiService.encodePassword(params.password, salt) 
     } 

     if (!user.save(flush: true)) { 
      render view: 'create', model: [user: user, authorityList: sortedRoles()] 
      return 
     } 

     addRoles(user) 
     flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])}" 
     redirect action: edit, id: user.id 
    } 

ed ecco un esempio di ciò che l'SPG assomiglia:

<table> 
     <tbody> 

      <s2ui:textFieldRow name='username' labelCode='user.username.label' bean="${user}" 
          labelCodeDefault='Username' value="${user?.username}"/> 

      <s2ui:passwordFieldRow name='password' labelCode='user.password.label' bean="${user}" 
           labelCodeDefault='Password' value="${user?.password}"/> 

      <s2ui:textFieldRow name='email' labelCode='user.email.label' bean="${user}" 
           labelCodeDefault='E-Mail' value="${user?.email}"/> 

      <s2ui:textFieldRow readonly='yes' name='area.name' labelCode='user.area.label' bean="${user}" 
           labelCodeDefault='Department' value="${area.name}"/> 


      <s2ui:checkboxRow name='enabled' labelCode='user.enabled.label' bean="${user}" 
          labelCodeDefault='Enabled' value="${user?.enabled}"/> 

      <s2ui:checkboxRow name='accountExpired' labelCode='user.accountExpired.label' bean="${user}" 
          labelCodeDefault='Account Expired' value="${user?.accountExpired}"/> 

      <s2ui:checkboxRow name='accountLocked' labelCode='user.accountLocked.label' bean="${user}" 
          labelCodeDefault='Account Locked' value="${user?.accountLocked}"/> 

      <s2ui:checkboxRow name='passwordExpired' labelCode='user.passwordExpired.label' bean="${user}" 
          labelCodeDefault='Password Expired' value="${user?.passwordExpired}"/> 
     </tbody> 
     </table> 

ho guardato in questo e credo che sia il modo in cui sto cercando di salvare un oggetto GORM e dovrei forse salvare il genitore (Regione) prima di tentare di salvare il utente. Tuttavia l'Area esisterà sempre prima che l'utente possa essere creato, quindi non ho bisogno che l'area venga creata di nuovo, come posso gestirla? Ho provato la funzione "withTransaction" con scarso successo anche

Sarei davvero grato di un aiuto su questo se possibile.

Grazie

EDIT ......

ho monitorato il problema a questa linea nel Controller:

RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt) 

Questo mi dicono che questa funzione sta chiamando un salvataggio funzione per l'oggetto utente, tuttavia con le relazioni in atto è necessario prima salvare l'Area. Qualcuno conosce SpringSecurityUi per aiutarmi in questo?

Grazie

+0

Inserire il server di sicurezza nel controller, non nella classe di dominio. – marko

+0

Potete fornirmi un esempio per favore? poiché il servizio di sicurezza delle molle è sempre stato lì – user723858

+0

L'errore non sarebbe correlato alla classe "com.website.Area" come dice l'errore? Grazie – user723858

risposta

7

Il messaggio di errore che si vede

object references an unsaved transient instance - save the transient instance before flushing: com.website.Area 

... succede quando stai cercando di salvare un genitore inesistente (cioè Area) da un bambino (i.e Utente) entità. È possibile che si verifichi un errore nel metodo RegistrationController.register come hai indicato, se è lì che stai salvando un nuovo utente.

RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt) 

È sufficiente aggiornare il codice di registrazione .registrare il metodo con la logica per assegnare l'area a un utente (supponendo che l'area sia già esistente) prima della chiamata registro - di seguito è riportato un esempio rapido.

class RegistrationController .. 
.. 
def area = Area.findByName(command.areaName) 
def user = lookupUserClass().newInstance(email: command.email, username: command.username, 
       accountLocked: true, enabled: true, area: area) 
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt) 

Un paio di note:

  • si passa indietro "area.name" dalla visualizzazione GSP, quindi avrai bisogno di aggiornare/ignorare il RegisterCommand per includere il Area nome
  • è l'uso di Area "nome" come identificatore sicuro? Nella tua definizione di classe non hai vincoli per indicare che il "nome" sarà unico. Forse passando di nuovo un Area id dal vostro punto di vista è più sicuro
  • Idealmente si dovrebbe gestire la Area ricerca con un editor di proprietà personalizzata - ecco un esempio: Grails command object data binding

In ogni modo, la speranza che aiuta.

+0

Life saver :-) Avevo già risolto il problema in una parte della soluzione, ma questo mi ha davvero aiutato a risolverne un'altra :-D – user723858

+0

La migliore risposta ... e una buona spiegazione per la domanda –

1

cercare di trasformare la dipendenza bidirezionale verso l'altro lato

class Areas { 

    String name 
    static belongsTo = [User] 
    static hasMany = [users:User] 
} 

Non dimenticare di rimuovere belongsTo da utente

1
class Areas { 
    String name 
    static belongsTo = [User] 
    static hasMany = [users:User] 
} 
Problemi correlati