[英]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.