2009-07-27 16 views
36

Ejemplo rápido: un usuario ingresa un nombre de usuario en un formulario, y necesito hacer ese nombre de usuario de texto antes de almacenarlo en la base de datos de la aplicación, de modo que quede permanentemente en minúscula.Ruby on Rails: ¿Puedo modificar los datos antes de guardarlos?

¿Dónde colocaría este código y cómo accedería a los datos para que se escriban en minúscula?

Gracias.

Respuesta

46

Se puede usar una de las devoluciones de llamada ActiveRecords en su modelo de usuario, por ejemplo, algo así:

before_save { |user| user.username = user.username.downcase } 
+1

Más sobre las devoluciones de llamada de ActiveRecord: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html – Zargony

+1

Si tiene muchos ganchos así y/o muchas operaciones realizadas en atributos, también puede crear métodos para ellos y darles los nombres del método en lugar de lambdas. También puede ver [attribute-filters] (http://rubydoc.info/gems/attribute-filters/1.2.2/) gem que simplifica ese proceso si tiene muchas devoluciones de llamada que están diseñadas para cambiar los atributos. – siefca

0

En el caso general, el botón de enviar en el formulario debe delegar a una acción del controlador donde params [: Nombre de usuario disponible. Podría minúsculas antes de hacer un SomeModel.update (params) o crear (params).

Entonces podría hacerlo en la acción del controlador.

+0

Debe pensar en las consecuencias de acoplar estrechamente el controlador y el modelo. ¿Qué sucede cuando dos controladores necesitan crear una instancia de este modelo? ¿Qué pasa con el uso de la consola para crear un usuario, y el desarrollador se olvida de que los nombres de usuario deberían estar ocultos? ¿Qué hay de las pruebas unitarias? Creo que un mejor enfoque es utilizar las devoluciones de llamada de ActiveRecord como lo sugiere effkay. –

+0

Sí, yo también lo voté. Mi razonamiento: siempre y cuando esté en un solo lugar, realmente no me importa. en realidad no parecía que hubiera múltiples lugares de la pregunta del OP ... así que fui por la cosa más simple que podría funcionar. También es posible que no siempre tenga un modelo ... en este escenario, sin embargo, parece que el OP debería estar usando uno. – Gishu

70

se deben sobrescribir el escritor atributo:

class User < ActiveRecord::Base 
    def username=(val) 
    write_attribute(:username, val.downcase) 
    end 
end 
+4

Sí, esta es la mejor solución. Garantizará la coherencia incluso antes de que un objeto se guarde en la base de datos. – molf

+0

¡Gracias me ayudó mucho resolviendo un problema que me estaba agotando! :) – Vicer

+1

¡Esta respuesta debe ser aceptada, muévela a la cima! – RonLugge

0

que sugeriría la adición de un Observer al modelo y hacer esta acción en el método before_save. Luego, se garantiza minar el nombre de usuario sin importar qué controlador o acción lo esté creando, y si hay un problema al realizar cualquier acción dentro del observador, se lanza una excepción y el objeto no se guardará.

Editar: Tenga en cuenta que usted no puede hacer un modelo.guardar dentro del before_save vinculado a ese modelo, de lo contrario terminará en un ciclo infinito. Tendrá que hacer un update_attributes o algo así.

11

En su modelo de usuario (modelos/user.rb), aprovechar las devoluciones de llamada ActiveRecord:

before_save do 
    self.username = self.username.downcase 
end 
+0

Esto no funciona en mi caso – Neeraj

4

pasé un tiempo buscando un bicho me quita de la utilización de este código. Mi base de datos estaba retrocediendo cada vez que traté de interceptar un atributo y cambiarlo a false antes de guardar.

Estoy contribuyendo mi respuesta aquí porque este hilo fue el primer resultado de Google para realizar esta tarea, pero no cubrió todo el problema false.

Si cualquiera de sus devoluciones de llamadas devuelve false, todo se retrotraerá en el archivo db.

Estaba tratando de configurar una oferta para que no se acepte en la base de datos o @offer.accepted = false. El problema era que esta línea hacía que todo el método devolviera falso y revertía todo el proceso.

me fijo lanzando en un rendimiento implícito true después

código que funcionó:

before_save {|offer| offer.accepted = false; true}

Para llevar: Sus devoluciones de llamada no pueden regresar false si se quiere que tengan éxito.

Fuente: rails 3 : Do i need to give return true in a before_save callback for an object.save to work?

1
def username=(str) 
super(str.downcase) 
end 

pensé que esto mucho más fácil.