ruby on rails - sobre - Diseño de parches de mono(o cualquier gema de Rails)
sintaxis ruby on rails (7)
Estoy usando la gema de autenticación Devise en mi proyecto Rails, y quiero cambiar las claves que está usando en las alertas flash. (Devise usa: aviso y: teclas de flash de alerta, pero quiero cambiarlas a: éxito y: error para que pueda mostrar bonitos cuadros verdes / rojos con Bootstrap )
Así que quiero poder anular de alguna manera el método DeviseController en DeviseController .
Aquí está el nuevo método:
def set_flash_message(key, kind, options = {})
if key == ''alert''
key = ''error''
elsif key == ''notice''
key = ''success''
end
message = find_message(kind, options)
flash[key] = message if message.present?
end
Pero simplemente no sé dónde ponerlo.
ACTUALIZAR:
Basándome en una respuesta, creé un archivo config / initializers / overrides.rb con el siguiente código:
class DeviseController
def set_flash_message(key, kind, options = {})
if key == ''alert''
key = ''error''
elsif key == ''notice''
key = ''success''
end
message = find_message(kind, options)
flash[key] = message if message.present?
end
end
Pero esto causa un error en cada acción de Devise:
Error de enrutamiento: método no definido ''prepend_before_filter'' para Devise :: SessionsController: Class
¿Qué hay de agregar el inicializador y el alias de anulación para los atributos del hash de flash, como esto:
class ActionDispatch::Flash::FlashHash
alias_attribute :success, :notice
alias_attribute :error, :alert
end
Esto debería permitir que su aplicación lea flash [: notice] o flash [: success] (flash.notice y flash.success)
Debe sobrescribir DeviseController mientras se mantiene alrededor de su superclase, en su inicializador.
Algo como:
class DeviseController < Devise.parent_controller.constantize
def set_flash_message(key, kind, options = {})
if key == ''alert''
key = ''error''
elsif key == ''notice''
key = ''success''
end
message = find_message(kind, options)
flash[key] = message if message.present?
end
end
En su archivo de inicializador:
module DeviseControllerFlashMessage
# This method is called when this mixin is included
def self.included klass
# klass here is our DeviseController
klass.class_eval do
remove_method :set_flash_message
end
end
protected
def set_flash_message(key, kind, options = {})
if key == ''alert''
key = ''error''
elsif key == ''notice''
key = ''success''
end
message = find_message(kind, options)
flash[key] = message if message.present?
end
end
DeviseController.send(:include, DeviseControllerFlashMessage)
Esto es bastante brutal pero hará lo que quieras. El mixin eliminará el método set_flash_message anterior, lo que obligará a las subclases a recurrir al método mixin.
Edición: self.included se llama cuando el mixin se incluye en una clase. El parámetro klass es la clase a la que se ha incluido la mezcla. En este caso, klass es DeviseController, y llamamos remove_method en él.
Este es el tipo de cosas que querrá poner en la carpeta de inicialización de rieles, ya que es una configuración personalizada para esta aplicación en particular, en segundo lugar, debe usar así:
class DeviseController
def set_flash_message(key, kind, options = {})
if key == ''alert''
key = ''error''
elsif key == ''notice''
key = ''success''
end
message = find_message(kind, options)
flash[key] = message if message.present?
end
end
entonces debería obtener el comportamiento esperado. Espero que ayude ya que no he probado, de no por favor dar una retroalimentación y le ayudaré a probar algo diferente.
Sé que este es un hilo antiguo, pero esto podría ser útil. Debería poder solicitar el archivo desde el directorio de gemas utilizando el motor llamado_de la ruta.
require File.expand_path(''../../app/helpers/devise_helper'',Devise::Engine.called_from) require File.expand_path(''../../app/controllers/devise_controller'',Devise::Engine.called_from) DeviseController.class_eval do # Your new methods here end
Si intenta reabrir una clase, es la misma sintaxis que declarar una nueva clase:
class DeviseController
end
Si este código se ejecuta antes de la declaración de clase real, hereda de Object en lugar de extender la clase declarada por Devise. En su lugar trato de usar lo siguiente
DeviseController.class_eval do
# Your new methods here
end
De esta manera, obtendrá un error si DeviseController
no ha sido declarado. Como resultado, probablemente terminará con
require ''devise/app/controllers/devise_controller''
DeviseController.class_eval do
# Your new methods here
end
Usar la respuesta de Rails 4 @aceofspades no me funcionó.
Seguí recibiendo ": cannot load such file -- devise/app/controllers/devise_controller (LoadError)
En lugar de atornillar con el orden de carga de los inicializadores, utilicé el gancho del evento to_prepare
sin una declaración de requerimiento. Asegura que el parche del mono ocurra antes de la primera solicitud. Este efecto es similar a after_initialize
hook, pero garantiza que los parches de mono se vuelvan a aplicar en el modo de desarrollo después de una recarga (en el modo prod, el resultado es idéntico).
Rails.application.config.to_prepare do
DeviseController.class_eval do
# Your new methods here
end
end
NB: la documentación de rieles en to_prepare
sigue siendo incorrecta: consulte este problema de Github