ruby - rails - rieles 3: ¿Debo dar una respuesta verdadera en una devolución de llamada before_save para que un object.save funcione?
rails before_update (4)
Class User
before_save :set_searchable
def set_searchable
self.searchable = true if self.status == :active
end
end
>> u = User.last
>> u.save
false
u.save siempre devuelve falso. Si elimino la función before_save, también funciona si doy una respuesta verdadera en la función before_save, funciona
¿Entonces necesito dar declaraciones de devolución en before_save? ¿ActiveRecord guarda un objeto si el before_save devuelve falso?
¿Dónde puedo ver una documentación completa sobre las devoluciones de llamada y su flujo de trabajo?
Gracias por adelantado
De: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Si una devolución de llamada before_ * devuelve falso, se cancelan todas las devoluciones de llamada posteriores y la acción asociada. Si una devolución de llamada after_ * devuelve falso, se cancelan todas las devoluciones de llamada posteriores. Las devoluciones de llamada generalmente se ejecutan en el orden en que se definen, con la excepción de las devoluciones de llamada definidas como métodos en el modelo, que se llaman los últimos.
Entonces sí.
La documentación dice
Si una devolución de llamada before_ * devuelve falso, se cancelan todas las devoluciones de llamada posteriores y la acción asociada. Si una devolución de llamada after_ * devuelve falso, se cancelan todas las devoluciones de llamada posteriores. Las devoluciones de llamada generalmente se ejecutan en el orden en que se definen, con la excepción de las devoluciones de llamada definidas como métodos en el modelo, que se llaman los últimos.
PERO
es posible que desee revisar esto (lo he probado yo mismo y el problema es 100% auténtico)
Además, también hay un error relacionado con before_save que quizás quieras saber. Consulta el comentario here
Como se dice en el comentario se observa a veces.
Hagas lo que hagas, ten en cuenta que hay algunos problemas con la devolución de llamada de Rails. Esto te ahorraría tiempo cuando te encontraras con uno de esos
No, no es necesario que devuelva true desde las devoluciones de llamada de Rails. No puede devolver nada en absoluto, o verdadero, o 3.141592, y aún se guardará. Lo único que importa es si devuelve falso, y esto solo se aplica antes de Rails 5. Devolver falso cancelaría el ahorro antes de Rails 5. Devolver true nunca tuvo ningún efecto.
Para Rails 5+, la nueva forma de bloquear la actualización es lanzar una excepción: throw(:abort)
. . Esto es más intuitivo y menos propenso a errores. El valor de retorno no tiene ningún efecto sobre si se guardará, a menos que configure el comportamiento heredado.
Es válido, y es una buena práctica de SECAR, simplemente continuar con su negocio y no devolver nada en absoluto; solo asegúrese de evitar devolver falsos accidentalmente de forma implícita si utiliza Rails anteriores. Por ejemplo:
# This is fine, record will be saved
def before_save
self.foo = ''bar'' # Implicitly returns ''bar''
end
# This is an accidental veto, record will not be saved
def before_save
Rails.logger.info ''user requested save''
self.fresh = false # Oops! Implicitly returns false
end
# One way to rectify the above example (another would be to re-order if it''s possible)
def before_save
Rails.logger.info ''user requested save''
self.fresh = false
return # Implicitly returns nil. Could also do `return true`
end
Lo que se tiene aquí es que puede olvidar que algunas funciones de tipo "de procedimiento" devolverán un booleano como una clase de código de estado o simplemente porque la implementación termina con un booleano como efecto secundario. Podría pensar que está mutando una cadena o algo así, pero termina vetando accidentalmente la devolución de llamada. Entonces, aunque creo que generalmente es demasiado ruidoso para regresar explícitamente de las devoluciones de llamada, sí es necesario tener cuidado con las devoluciones implícitas. Una de las razones por las que la gente defendía que se hiciera realidad era protegerse contra este problema.
Otra forma más limpia de establecer columnas booleanas sin return
es usar tap
def set_searchable
self.tap{|u| u.searchable = status.eql?(:active) }
end