Devise authentication - devise_error_messages! in

2019-08-02 11:48发布

问题:

devise_error_messages! in a view causes

undefined method 'errors' for nil:NilClass

after render :new in create method. This started happening after I inherited RegistrationsController from "Devise::RegistrationsController" instead of "ApplicationController". Initial rendering of "new" method does not cause any exceptions.

Overridden registrations controller:

class RegistrationsController < Devise::RegistrationsController
  def create
    begin
      raise I18n.t("registration_disabled") unless registration_enabled?
      ....................
    rescue => ex
      flash[:alert] = ex.message
      render :new
    end
  end
end

The view registrations/new.html.erb:

<h2><%= I18n.t("sign_up_title") %></h2>

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
    <%= devise_error_messages! %>

    <div><%= f.label :login, I18n.t("the_login") %> <span class="mandatory">*</span><br />
      <%= f.text_field :login %></div>

    <div><%= f.label :password, I18n.t("password") %> <span class="mandatory">*</span><br />
      <%= f.password_field :password %></div>

    <div><%= f.label :password_confirmation, I18n.t("password_confirmation") %> <span class="mandatory">*</span><br />
      <%= f.password_field :password_confirmation %></div>

    <div><%= f.submit from_admin? ? I18n.t("sign_up_other") : I18n.t("sign_up") %></div>
    <p class="mandatory">* - <%= I18n.t("mandatory_fields") %></p>
<% end %>

<%= render "devise/links" %>

回答1:

I believe it's because you're raising the exception before the object (devise calls it the resource) is created. And it is needed by the devise_error_messages helper.

If you want to prevent access to the registration, there are other ways to achieve this:

One way could be :

class RegistrationsController < Devise::RegistrationsController
  def create
    if registration_enabled?
      super
    else
      flash[:alert] = I18n.t("registration_disabled")
      redirect_to action: :new
    end
  end
end

I'm not 100% sure if this would work but this idea is to render the view with the flash if user can't register, so this would behave as the "initial rendering"

EDIT : Actually I believe that changing your

render action: :new

to

redirect_to action: :new

would be enough to prevent the error as the redirect_to will execute the methode whereas the render just render the associate view.