web-dev-qa-db-fra.com

Singe patcher Devise (ou n'importe quel joyau Rails)

J'utilise la gemme Devise authentication dans mon projet Rails et je souhaite modifier les clés utilisées dans les alertes flash. (Devise utilise: avis et: touches flash d’alerte, mais je souhaite les changer en: succès et: erreur pour pouvoir afficher de jolies cases vert/rouge avec Bootstrap .)

Je souhaite donc pouvoir en quelque sorte remplacer la méthode set_flash_message dans DeviseController .

Voici la nouvelle méthode:

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

Mais je ne sais pas où le mettre. 


UPDATE:

Sur la base d'une réponse, j'ai créé un fichier config/initializers/overrides.rb avec le code suivant:

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

Mais cela provoque une erreur sur chaque action Devise: 

Erreur de routage: méthode non définie 'prepend_before_filter' pour Devise :: SessionsController: Class

21
Yarin

Si vous essayez de rouvrir une classe, la syntaxe est la même que pour déclarer une nouvelle classe:

class DeviseController
end

Si ce code est exécuté avant la déclaration de classe réelle, il hérite de Object au lieu d'étendre la classe déclarée par Devise. Au lieu de cela, j'essaie d'utiliser ce qui suit

DeviseController.class_eval do
  # Your new methods here
end

De cette façon, vous obtiendrez une erreur si DeviseController n'a pas été déclaré. En conséquence, vous finirez probablement avec

require 'devise/app/controllers/devise_controller'

DeviseController.class_eval do
  # Your new methods here
end
56
aceofspades

Utiliser Rails 4 @aceofspades answer n'a pas fonctionné pour moi. 

Je continuais à avoir besoin ': cannot load such file -- devise/app/controllers/devise_controller (LoadError) 

Au lieu de viser avec l'ordre de chargement des initialiseurs, j'ai utilisé le hook d'événement to_prepare sans instruction require. Cela garantit que la correction du singe se produit avant la première demande. Cet effet est similaire à after_initialize hook, mais garantit que la correction de singe est réappliquée en mode développement après un rechargement (en mode prod, le résultat est identique).

Rails.application.config.to_prepare do
  DeviseController.class_eval do
    # Your new methods here
  end
end

N.B. la documentation de Rails sur to_prepare est toujours incorrecte: consultez cette question de Github

12
ARO

Qu'en est-il de l'ajout de l'initialiseur de substitution et de l'alias pour les attributs du hachage flash, comme ceci:

class ActionDispatch::Flash::FlashHash
  alias_attribute :success, :notice
  alias_attribute :error, :alert
end

Cela devrait permettre à votre application de lire flash [: notice] ou flash [: succès] (flash.notice et flash.success).

3
Laura Popa

Dans votre fichier d'initialisation: 

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)

C'est assez brutal mais fera ce que vous voulez. Le mixin supprimera la méthode précédente set_flash_message, forçant les sous-classes à revenir à la méthode mixin.

Edit: Self.included est appelé lorsque le mixin est inclus dans une classe. Le paramètre klass est la classe dans laquelle le mixin a été inclus. Dans ce cas, klass est DeviseController et nous appelons remove_method dessus. 

3
RedXVII

Vous devez écraser DeviseController tout en conservant sa super-classe dans votre initialiseur.

Quelque chose comme:

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
1
Borski

Je sais que c'est un vieux fil, mais cela pourrait quand même être utile. Vous devriez pouvoir demander le fichier depuis le répertoire gem en utilisant le moteur appelé chemin_du_fichier.

 nécessite File.expand_path ('../../ app/helpers/devise_helper', Devise :: Engine.called_from) 
 nécessite File.expand_path ('../../ app/controllers/devise_controller ', Devise :: Engine.called_from).
0
userbard

C’est le genre de chose que vous voudrez mettre sur le dossier d’initialisation Rails, car c’est une configuration personnalisée pour cette application en particulier, vous devriez ensuite l’utiliser comme suit:

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

alors, vous devriez avoir le comportement attendu. J'espère que ça m'aidera car je n'ai pas testé, ni donné de feedback, et je vous aiderai à essayer quelque chose de différent.

0
vinicius gati