[英]Monkey patching Devise (or any Rails gem)
I'm using the Devise authentication gem in my Rails project, and I want to change the keys it's using in flash alerts. 我在我的Rails项目中使用Devise身份验证gem,我想更改它在闪存警报中使用的密钥。 (Devise uses :notice and :alert flash keys, but I want to change them to :success and :error so that I can display nice green/red boxes with Bootstrap .)
(设计使用:通知和:警告闪存键,但我想将它们更改为:成功和:错误,以便我可以使用Bootstrap显示漂亮的绿色/红色框。)
So I want to be able to somehow override the set_flash_message
method in DeviseController . 所以,我希望能够以某种方式覆盖
set_flash_message
方法DeviseController 。
Here's the new method: 这是新方法:
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
But I just don't know where to put it. 但我只是不知道该把它放在哪里。
UPDATE: 更新:
Based on an answer I created a config/initializers/overrides.rb file with the following code: 基于答案,我使用以下代码创建了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
But this causes an error on every Devise action: 但这会导致每个Devise操作出错:
Routing Error: undefined method 'prepend_before_filter' for Devise::SessionsController:Class
路由错误:Devise :: SessionsController:Class的未定义方法'prepend_before_filter'
If you try to reopen a class, it's the same syntax as declaring a new class: 如果您尝试重新打开一个类,则它与声明一个新类的语法相同:
class DeviseController
end
If this code is executed before the real class declaration, it inherits from Object instead of extending the class declared by Devise. 如果此代码在实际类声明之前执行,则它继承自Object而不是扩展Devise声明的类。 Instead I try to use the following
相反,我尝试使用以下内容
DeviseController.class_eval do
# Your new methods here
end
This way, you'll get an error if DeviseController
has not been declared. 这样,如果尚未声明
DeviseController
,您将收到错误。 As a result, you'll probably end up with 结果,你可能会最终得到
require 'devise/app/controllers/devise_controller'
DeviseController.class_eval do
# Your new methods here
end
Using Rails 4 @aceofspades answer didn't work for me. 使用Rails 4 @aceofspades的答案对我不起作用。
I kept getting require': cannot load such file -- devise/app/controllers/devise_controller (LoadError)
我一直得到要求':
cannot load such file -- devise/app/controllers/devise_controller (LoadError)
Instead of screwing around with load order of initializers I used the to_prepare
event hook without a require statement. 我没有使用require语句来使用
to_prepare
事件挂钩而不是使用初始化器的加载顺序。 It ensures that the monkey patching happens before the first request. 它确保猴子修补在第一次请求之前发生。 This effect is similar to
after_initialize
hook, but ensures that monkey patching is reapplied in development mode after a reload (in prod mode the result is identical). 此效果类似于
after_initialize
挂钩,但确保在重新加载后在开发模式下重新应用猴子修补(在prod模式下结果相同)。
Rails.application.config.to_prepare do
DeviseController.class_eval do
# Your new methods here
end
end
NB the rails documentation on to_prepare
is still incorrect: See this Github issue 注意
to_prepare
上的rails文档仍然不正确:请参阅此Github问题
What about adding in the override initializer and alias for the attributes of the flash hash, like this: 如何添加覆盖初始化程序和flash哈希属性的别名,如下所示:
class ActionDispatch::Flash::FlashHash
alias_attribute :success, :notice
alias_attribute :error, :alert
end
This should allow your application to read flash[:notice] or flash[:success](flash.notice and flash.success) 这应该允许你的应用程序读取flash [:notice]或flash [:success](flash.notice和flash.success)
In your initializer file : 在初始化文件中:
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)
This is pretty brutal but will do what you want. 这是非常残酷的,但会做你想要的。 The mixin will delete the previous set_flash_message method forcing the subclasses to fall back to the mixin method.
mixin将删除先前的set_flash_message方法,强制子类回退到mixin方法。
Edit: self.included is called when the mixin is included in a class. 编辑:当mixin包含在类中时调用self.included。 The klass parameter is the Class to which the mixin has been included.
klass参数是包含mixin的Class。 In this case, klass is DeviseController, and we call remove_method on it.
在这种情况下,klass是DeviseController,我们在其上调用remove_method。
You need to overwrite DeviseController while keeping around its superclass, in your initializer. 您需要在初始化程序中覆盖DeviseController,同时保留其超类。
Something like: 就像是:
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
This is the kind of thing that you will want to put on initialize rails folder, because it's a custom config for this application in particular, second you should use like so: 这是你想要初始化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
then you should get the expected behavior. 那么你应该得到预期的行为。 hope it helps since i dont tested, of not pls give a feedback and i will help you try something diferent.
希望它有所帮助,因为我没有测试,不请给出反馈,我会帮助你尝试不同的东西。
I know this is an old thread but this might still be helpful. 我知道这是一个旧线程,但这可能仍然有用。 You should be able to require the file from the gem directory using the engine called_from path.
您应该能够使用引擎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.