25

我在我的 Rails 项目中使用Devise身份验证 gem,我想更改它在 Flash 警报中使用的密钥。(设计使用 :notice 和 :alert flash 键,但我想将它们更改为 :success 和 :error 以便我可以使用Bootstrap显示漂亮的绿色/红色框。)

所以我希望能够以某种方式覆盖DeviseControllerset_flash_message中的方法。

这是新方法:

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::SessionsController:Class 的未定义方法“prepend_before_filter”

4

7 回答 7

60

如果您尝试重新打开一个类,它与声明一个新类的语法相同:

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
于 2013-06-20T17:49:54.820 回答
15

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

我不断收到要求':cannot load such file -- devise/app/controllers/devise_controller (LoadError)

我没有搞乱初始化程序的加载顺序,而是使用了to_prepare没有 require 语句的事件挂钩。它确保猴子修补发生在第一个请求之前。此效果类似于after_initialize钩子,但确保重新加载后在开发模式下重新应用猴子补丁(在生产模式下结果相同)。

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

NB 上的 rails 文档to_prepare仍然不正确:请参阅此Github 问题

于 2014-10-21T08:46:47.597 回答
4

在您的初始化程序文件中:

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。

于 2013-06-20T09:51:38.027 回答
3

为闪存哈希的属性添加覆盖初始化程序和别名怎么样,如下所示:

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

这应该允许您的应用程序读取 flash[:notice] 或 flash[:success](flash.notice 和 flash.success)

于 2013-06-18T17:14:35.563 回答
1

您需要在初始化程序中覆盖 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
于 2013-06-18T20:46:31.727 回答
0

这是您要放在初始化 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

那么你应该得到预期的行为。希望它有所帮助,因为我没有测试过,请不要提供反馈,我会帮助你尝试不同的东西。

于 2013-06-15T01:24:43.663 回答
0

我知道这是一个旧线程,但这可能仍然有帮助。您应该能够使用名为_from 路径的引擎从 gem 目录中获取文件。

  需要 File.expand_path('../../app/helpers/devise_helper',Devise::Engine.called_from)
  需要 File.expand_path('../../app/controllers/devise_controller',Devise::Engine.called_from)

  DeviseController.class_eval 做
    # 你的新方法在这里
  结尾
于 2017-12-13T23:02:41.837 回答