Monkey patching Devise (or any Rails gem)

Używam gem uwierzytelnianiaDevise w moim projekcie Rails i chcę zmienić klucze, których używa w alertach flash. (Devise używa klawiszy :notice i: alert flash, ale chcę je zmienić na: success I: error, aby móc wyświetlać ładne zielone / czerwone pola z Bootstrap .)

Więc chcę być w stanie jakoś nadpisać metodę set_flash_message w DeviseController .

Oto nowa metoda:

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
Ale nie wiem, gdzie to umieścić.

UPDATE:

Na podstawie odpowiedzi utworzyłem config/initializers / overrides.plik rb o następującym kodzie:

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

Ale to powoduje błąd przy każdej akcji Devise:

Routing Error: undefined method 'prepend_before_filter' for Devise:: SessionsController:Class

Author: Yarin, 2013-06-15

7 answers

Jeśli spróbujesz ponownie otworzyć klasę, będzie to taka sama składnia jak deklarowanie nowej klasy:

class DeviseController
end

Jeśli ten kod jest wykonywany przed rzeczywistą deklaracją klasy, dziedziczy po obiekcie zamiast rozszerzać klasę zadeklarowaną przez Devise. Zamiast tego staram się użyć następującego

DeviseController.class_eval do
  # Your new methods here
end

W ten sposób otrzymasz błąd, jeśli DeviseController nie został zadeklarowany. W rezultacie prawdopodobnie skończysz z

require 'devise/app/controllers/devise_controller'

DeviseController.class_eval do
  # Your new methods here
end
 55
Author: aceofspades,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 17:49:54

Używanie Rails 4 @ aceofspades answer Nie działało dla mnie.

/ Align = "left" / ': cannot load such file -- devise/app/controllers/devise_controller (LoadError)

Zamiast obijać się o kolejność ładowania inicjalizatorów użyłem Hooka to_prepare zdarzenia bez instrukcji require. Zapewnia to, że łatanie małp odbywa się przed pierwszym żądaniem. Efekt ten jest podobny do Hooka after_initialize, ale zapewnia, że monkey patching jest ponownie stosowany w trybie deweloperskim po przeładowaniu (w trybie prod wynik jest identyczny).

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

N. B. szyny dokumentacja na {[2] } jest nadal Niepoprawna: zobacz ten problem z Githubem

 12
Author: ARO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-30 22:07:19

A co z dodaniem w nadpisywaniu inicjalizatora i aliasu dla atrybutów hasha Flasha, jak to:

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

To powinno pozwolić Twojej aplikacji odczytać flash [: notice] lub flash[:success] (flash.uwaga i błysk.sukces)

 3
Author: Laura Popa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 17:14:35

W pliku inicjalizatora:

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)
To dość brutalne, ale zrobi to, co chcesz. Mixin usunie poprzednią metodę set_flash_message, zmuszając podklasy do powrotu do metody mixin.

Edytuj: siebie.included jest wywoływany, gdy mixin jest zawarty w klasie. Parametr klass jest klasą, do której włączono mixin. W tym przypadku klass jest Devisecontrollerem i wywołujemy na nim remove_method.

 3
Author: RedXVII,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 14:53:56

Musisz nadpisać DeviseController, zachowując jego superklasę w swoim inicjalizatorze.

Coś w stylu:

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
Author: Borski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 20:46:31

Jest to coś, co chcesz umieścić w folderze initialize rails, ponieważ jest to niestandardowa konfiguracja dla tej aplikacji, po drugie powinieneś użyć tak:

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

Następnie należy uzyskać oczekiwane zachowanie. mam nadzieję, że to pomaga, ponieważ nie testowałem, nie pls daj opinię, a ja pomogę ci spróbować czegoś innego.

 0
Author: vinicius gati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-16 14:52:29

Wiem, że to stary wątek, ale to może być pomocne. Powinieneś być w stanie zażądać pliku z katalogu gem przy użyciu silnika o nazwie path_from.

  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
 0
Author: userbard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-13 23:02:41