覆盖Devise控制器的问题

时间:2012-01-20 17:11:41

标签: ruby-on-rails devise controllers override

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

我试图以这种方式覆盖Devise::ConfirmationsController 1

# 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?方法在InternalHelpers 2中定义,这就是为什么我尝试添加include Devise::Controllers::InternalHelpers

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

[编辑] Devise的版本是1.4.9 Rails是3.0.10

2 个答案:

答案 0 :(得分:2)

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

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

如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,但是我无法让它工作,我不确定在我从过滤方法中得出它之后我仍然可以改变渲染视图......欢迎评论!

答案 1 :(得分:1)

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

因此,如果您只想设置Flash消息,请查看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