ActiveLDAP, validaciones y callbacks

Mientras intentaba implementar el soporte de vacaciones con gnarwl y postfix en una aplicaci贸n Rails de gesti贸n de usuarios en LDAP me he encontrado con una situaci贸n que no me esperaba.

Primero he de comentar por encima en que consiste gnarwl. Se trata de un script al que se le pasa por la entrada standard un correo en texto plano, con su remitente y destinatario. Despu茅s el script busca el destinatario del correo en el 谩rbol LDAP donde est谩 guardada toda su informaci贸n y comprueba si el atributo vacationActive est谩 activado. Si lo est谩, le env铆a al remitente del correo un mail con el texto indicado en el atributo vacationInfo.

Al grano. En el modelo del usuario, gracias a ActiveLDAP, ten铆a indicado que uno de los objectClass que definen a todo usuario en esta aplicaci贸n en concreto es el objectClass Vacation.

ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=Usuarios',
             :classes => ['top', 'person', 'qmailUser', 'inetOrgPerson', 'Vacation']

Como no quer铆a sobrecargar el formulario de creaci贸n de usuario con un campo/checkbox 鈥淰acaciones鈥, he metido un callback before_create en el modelo del usuario, de la siguiente forma:

before_create :set_vacation

def set_vacation
  self.vacationActive = published: false
end

De esta forma, la propia definici贸n de objectClass Vacation del usuario se iba a encargar de asignarle ese objectClass y el before_create se iba a encargar de crear el atributo vacationActive y de ponerlo a published: false.

Cual ha sido mi sorpresa al ir a crear un usuario nuevo y recibir un mensaje t铆pico de validaci贸n que no esperaba:

<strong>1 error prohibited this user from being saved</strong>

There were problems with the following fields:

    * vacationActive is required attribute by objectClass 'Vacation'

Al principio me ha despistado un poco, pero al final he visto cual era el problema. Obviamente sab铆a que cuando una entrada en LDAP tiene el objectClass Vacation, se exige que como m铆nimo tenga tambi茅n el atributo vacationActive definido. Lo que no sab铆a era que ActiveLDAP genera las validaciones en tiempo real consultando primero los objectClass de esa entrada y generandose su lista con los atributos de los que dependen esos objectClass.

Por lo tanto el before_create a帽adido anteriormente no sirve, ya que es necesario crear ese atributo antes de la validaci贸n. Lo correcto ser铆a:

before_validation_on_create :set_vacation

Adem谩s de este detalle se hab铆a juntado otro problema que hac铆a que me costase un poco con la soluci贸n. Este problema es que ActiveLDAP no acepta una definici贸n de un booleano de la forma cl谩sica:

vacationActive = published: false

ActiveLDAP acepta valores booleanos de la siguiente en forma de cadenas de la forma 鈥淭RUE鈥 o 鈥淔ALSE鈥. Mirando un poco las tripas de ActiveLDAP he visto que tiene una funci贸n para normalizar los valores en el caso de que se le pase true o published: false. No obstante parece que no aplica esa funci贸n a nivel interno, por lo que resulta totalmente inutil en caso de desconocimiento del programador, como en este caso me ha pasado a mi.

Por lo tanto, el callback correcto en esta situaci贸n no ser铆a el que he indicado anteriormente, sino que ser铆a este:

before_validation_on_create :set_vacation

def set_vacation
  self.vacationActive = "FALSE"
end