簡體   English   中英

猴子修補Devise(或任何Rails gem)

[英]Monkey patching Devise (or any Rails gem)

我在我的Rails項目中使用Devise身份驗證gem,我想更改它在閃存警報中使用的密鑰。 (設計使用:通知和:警告閃存鍵,但我想將它們更改為:成功和:錯誤,以便我可以使用Bootstrap顯示漂亮的綠色/紅色框。)

所以,我希望能夠以某種方式覆蓋set_flash_message方法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

但我只是不知道該把它放在哪里。


更新:

基於答案,我使用以下代碼創建了config / initializers / overrides.rb文件:

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

但這會導致每個Devise操作出錯:

路由錯誤:Devise :: SessionsController:Class的未定義方法'prepend_before_filter'

如果您嘗試重新打開一個類,則它與聲明一個新類的語法相同:

class DeviseController
end

如果此代碼在實際類聲明之前執行,則它繼承自Object而不是擴展Devise聲明的類。 相反,我嘗試使用以下內容

DeviseController.class_eval do
  # Your new methods here
end

這樣,如果尚未聲明DeviseController ,您將收到錯誤。 結果,你可能會最終得到

require 'devise/app/controllers/devise_controller'

DeviseController.class_eval do
  # Your new methods here
end

使用Rails 4 @aceofspades的答案對我不起作用。

我一直得到要求': cannot load such file -- devise/app/controllers/devise_controller (LoadError)

我沒有使用require語句來使用to_prepare事件掛鈎而不是使用初始化器的加載順序。 它確保猴子修補在第一次請求之前發生。 此效果類似於after_initialize掛鈎,但確保在重新加載后在開發模式下重新應用猴子修補(在prod模式下結果相同)。

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

注意to_prepare上的rails文檔仍然不正確:請參閱此Github問題

如何添加覆蓋初始化程序和flash哈希屬性的別名,如下所示:

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

這應該允許你的應用程序讀取flash [:notice]或flash [:success](flash.notice和flash.success)

在初始化文件中:

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)

這是非常殘酷的,但會做你想要的。 mixin將刪除先前的set_flash_message方法,強制子類回退到mixin方法。

編輯:當mixin包含在類中時調用self.included。 klass參數是包含mixin的Class。 在這種情況下,klass是DeviseController,我們在其上調用remove_method。

您需要在初始化程序中覆蓋DeviseController,同時保留其超類。

就像是:

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

這是你想要初始化rails文件夾的那種東西,因為它特別是這個應用程序的自定義配置,其次你應該這樣使用:

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

那么你應該得到預期的行為。 希望它有所幫助,因為我沒有測試,不請給出反饋,我會幫助你嘗試不同的東西。

我知道這是一個舊線程,但這可能仍然有用。 您應該能夠使用引擎called_from path從gem目錄中請求該文件。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM