Есть несколько вещей, которые, я думаю, нужно решить.
1) Инициализировать ресурс в действии change_password
Сбой вызова devise_error_messages!
, потому что вы не инициализируете resource
(ваш экземпляр модели пользователя) в действии RegistrationsController#change_password
. Один из способов сделать это - убедиться, что фильтр authenticate_scope!
before, реализованный в Devise :: RegistrationsController, вызывается в действии change_password
. Попробуйте что-то подобное в вашем контроллере RegistrationsController.
class RegistrationsController < Devise::RegistrationsController
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy, :change_password]
def create
...
end
end
Если это не сработает, вы можете просто позвонить authenticate_scope!
в начале вашего действия change_password
.
2) Перенаправить на change_password.html.erb в случае сбоя
Как правило, действие Devise::RegistrationsController#edit
и ваше действие RegistrationsController#change_password
отправляют форму в действие Devise::RegistrationsController#update
. Что вы хотите сделать, так это убедиться, что в случае сбоя обновления, если отправка формы происходит из действия Devise::RegistrationsController#edit
, вы визуализируете представление registrations/edit.html.erb
и, аналогично, если отправка формы происходит из действия RegistrationsController#change_password
, вы рендер registrations/change_password.html.erb
вид.
Существуют различные способы сделать это, включая использование флэш-хэша для установки ключа в действии RegistrationsController#change_password
(например, flash[:change_password] = true
), а затем проверки на наличие этого ключа, если во время обновления возникает ошибка. Другой подход заключается в использовании скрытого поля в форме change_password, а затем аналогичным образом, если во время обновления происходит ошибка, проверьте наличие этого скрытого поля в хэше params. Как то так.
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name),
:html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<%= hidden_field_tag :change_password, true %>
В любом случае вам нужно будет переопределить действие Devise :: RegistrationsController # udpate. Примерно так:
class RegistrationsController < Devise::RegistrationsController
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy, :change_password]
def update
if resource.update_with_password(params[resource_name])
set_flash_message :notice, :updated if is_navigational_format?
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords(resource)
respond_with_navigational(resource) do
if params[:change_password] # or flash[:change_password]
render_with_scope :change_password
else
render_with_scope :edit
end
end
end
end
end
Дайте это попробовать, но я думаю, что это должно вернуть вас в нужное русло.