【问题标题】:Issues with overriding Devise controllers覆盖设计控制器的问题
【发布时间】:2012-01-20 17:11:40
【问题描述】:

我正在尝试覆盖 Devise 控制器以进行一些小的更改,例如,在为未注册的电子邮件地址请求确认电子邮件时添加一条消息。

我试图用这种方式覆盖Devise::ConfirmationsController1

# app/controllers/confirmations_controller.rb
class ConfirmationsController < Devise::ConfirmationsController

  include Devise::Controllers::InternalHelpers # tried to add this, no success

  def create
    self.resource = resource_class.send_confirmation_instructions(params[resource_name])

    if successfully_sent?(resource)
      respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
    else
      respond_with(resource)
    end
  end

end

我认为我正确添加了路线:

devise_for :users, :controllers => { :confirmations => "confirmations" }

我的控制器方法被调用,但是它引发了这个异常:

NoMethodError in ConfirmationsController#create

undefined method `successfully_sent?' for #<ConfirmationsController:0x007fa49e229030>

在我重写的控制器中,我只是复制了Devise:: ConfirmationsController#create 的代码,它本身调用了successfully_sent?(resource)

successfully_sent?方法定义在InternalHelpers2中,这就是我尝试添加include Devise::Controllers::InternalHelpers的原因

这不是我第一次尝试覆盖 Devise 控制器,也不是我第一次失败。我总是设法找到解决方法,但我想了解我缺少什么......提前感谢您的帮助!

[编辑] 设计版本为 1.4.9 Rails 是 3.0.10

【问题讨论】:

  • 您使用的是什么版本的设计?您实际上是使用已安装的 Devise 版本的“bundle open devise”(或等效的)复制代码,还是只是从互联网上的某个地方复制代码?我没有看到成功发送?在我的 Devise 版本中定义。
  • 已经使用 rake routes 检查了路由
  • @Kyle:确实是我新手的错误!我正在查看 Github 上的最后一个提交版本,这不是我正在使用的版本...感谢您的帮助,我会回答这个问题,所以...谢谢!
  • @JudeArasu:不是路由问题,我在routes.rb 文件中正确添加了自定义设计路由,并且我的控制器被正确调用。

标签: ruby-on-rails devise controllers overriding


【解决方案1】:

嗯,感谢Kyle在我问题的cmets中的帮助,我会把这个初学者的错误的正确答案写出来。

我没有查看我自己的 Devise 版本来覆盖控制器,而是查看了 Devise 的 Github 存储库。由于我试图覆盖的控制器在我的版本和上次提交的版本之间发生了变化,所以我试图使用的辅助方法根本没有在我的版本中定义......

正如 Kyle 所说,您可以使用 bundle open devise 查看您实际使用的 gem 的代码,或者您可以使用 gem list devise 查看其版本号并在 Github 上找到此版本的代码 (对于 Devise,他们为每个版本设置了标签,以便您可以通过选择相应的标签来浏览 1.4.9 版的代码。

这样做,我会用以下代码覆盖我的控制器的 create 方法:

def create
  self.resource = resource_class.send_confirmation_instructions(params[resource_name])

  if successful_and_sane?(resource)
    set_flash_message(:notice, :send_instructions) if is_navigational_format?
    respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
  else
    respond_with_navigational(resource){ render_with_scope :new }
  end
end

它使用successful_and_sane? 而不是successfully_sent? ...

要总结这个答案,可能有比覆盖它更好的方法向这个方法添加一个 flash 消息。 jarrad 建议使用around_filter,但我还不能让它工作,而且我不确定在从过滤器方法生成它后我是否仍然可以更改渲染视图...欢迎评论!

【讨论】:

    【解决方案2】:

    这可能无法帮助您理解为什么覆盖 Devise 控制器会失败,但它会使您的代码保持干燥,因为您不需要从 Devise::ConfirmationsController#crete 复制代码

    所以,如果你只是想设置闪信,看Filters for ActionControllers

    具体看一下周边滤镜:

    class ConfirmationsController < Devise::ConfirmationsController
      around_filter :my_custom_stuff, :only => :create
    
      private
    
      def my_custom_stuff
        # do your thing here...
      end
    end
    

    【讨论】:

    • 我会写另一个更符合我的问题的答案,但我喜欢你的建议,我们会使用它,所以也谢谢! (并为此帮助提示 +1)。
    • 好吧,我找不到如何从 around_filter 中添加 Flash 消息。我想知道这是否可能。当我在 around filter 方法中调用 yield 时,视图会被渲染,所以我(还)看不到如何更改内容以添加 flash 消息。如果你能在这方面帮助我,那就太好了。
    猜你喜欢
    • 1970-01-01
    • 2015-04-26
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 2011-12-25
    相关资源
    最近更新 更多