Rails add new view to devise

2019-07-21 12:19发布

问题:

I have generated views with this command after I installed devise

rails generate devise:views

and I override registration controller by

class RegistrationsController < Devise::RegistrationsController

  def sign_up2

  end
end

And updated routes.rb with

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

I expected to see a new route/view of

  /users/sign_up2

but I don't see it And here routes for devise

        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        registrations#cancel
       user_registration POST   /users(.:format)               registrations#create
   new_user_registration GET    /users/sign_up(.:format)       registrations#new
  edit_user_registration GET    /users/edit(.:format)          registrations#edit
                         PATCH  /users(.:format)               registrations#update
                         PUT    /users(.:format)               registrations#update
                         DELETE /users(.:format)               registrations#destroy

But I would like a new view and route

Update: issue when I load view

First argument in form cannot contain nil or be empty

in this line

<%= form_for(resource, :as => resource_name,:html => { :class => "form-horizontal col-sm-12",:role=>"form"}, :url => user_registration_path(resource_name)) do |f| %>

回答1:

Invoke a devise_scope block and declare your custom route within:

devise_for :users, :controllers => { :registrations => "registrations" }  
devise_scope :user do
  get "users/sign_up2"=> "users/registrations#sign_up2", :as => "sign_up2_registration"
end

The section on Configuring routes in the documentation provides the following explanation of devise_scope:

If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a devise_scope block in the router

Previously, Devise allowed custom routes to be passed as a block to devise_for, but this behavior has been deprecated.

UPDATE:

To address the First argument in form cannot contain nil or be empty error, you need to ensure that your custom sign_up2 action is properly setting the resource variable. Assuming you want to mimic the registrations/new action, you can do something akin to the following:

def sign_up2
    build_resource({})
    respond_with self.resource
end

This ensures that the resource variable in your view is not nil and will not throw the exception you're currently witnessing.

Alternatively, depending on the behavior you're trying to evince, you can set your own instance variable in the custom controller action, then pass it as the resource to your form_for tag:

# app/controllers/users/registrations_controller.rb
def sign_up_2
    @new_registrant = Registrant.new
end

# app/views/users/sign_up2.html.erb
<%= form_for(@new_registrant, :as => resource_name,:html => { :class => "form-horizontal col-sm-12",:role=>"form"}, :url => user_registration_path(resource_name)) do |f| %>

However, if you follow this approach, you should consider why you need to roll this into Devise. Devise, by default, assigns the resource variable via the build_resource function. If you're going to override/bypass this function, you should consider abstracting this entire functionality out of Devise since you're totally circumventing its default behavior.