Làm cách nào để xóa tuyến đường Devise để đăng ký?


147

Tôi đang sử dụng Devise trong ứng dụng Rails 3, nhưng trong trường hợp này, người dùng hiện tại phải được tạo bởi người dùng hiện tại, người sẽ xác định những quyền mà anh ấy / cô ấy sẽ có.

Vì điều này, tôi muốn:

  • Để xóa tuyến đường cho người dùng đăng ký .
  • Để vẫn cho phép người dùng chỉnh sửa hồ sơ của họ (thay đổi địa chỉ email và mật khẩu) sau khi họ đã đăng ký

Tôi có thể làm cái này như thế nào?

Hiện tại, tôi đang loại bỏ tuyến đường này một cách hiệu quả bằng cách đặt các mục sau devise_for :users:

match 'users/sign_up' => redirect('/404.html')

Điều đó hiệu quả, nhưng tôi tưởng tượng có một cách tốt hơn, phải không?

Cập nhật

Như Benoit Garret đã nói, giải pháp tốt nhất trong trường hợp của tôi là bỏ qua việc tạo các tuyến đăng ký và chỉ tạo những thứ tôi thực sự muốn.

Để làm điều đó, trước tiên tôi chạy rake routes, sau đó sử dụng đầu ra để tạo lại những cái tôi muốn. Kết quả cuối cùng là thế này:

devise_for :users, :skip => [:registrations] 
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

Lưu ý rằng:

  • Tôi vẫn còn :registerabletrong Usermô hình của tôi
  • devise/registrations xử lý cập nhật email và mật khẩu
  • Cập nhật các thuộc tính người dùng khác - quyền, v.v. - được xử lý bởi một bộ điều khiển khác

Câu trả lời thực tế:

Xóa tuyến đường cho các đường dẫn Devise mặc định; I E:

devise_for :users, path_names: {
  sign_up: ''
}

4
Tôi thực sự nghĩ rằng giải pháp ban đầu của bạn đơn giản và rõ ràng hơn nhiều. Có bất kỳ vấn đề thực sự với nó bảo mật khôn ngoan?
phản đối

Vì một số lý do, giải pháp cập nhật của bạn liên tục xuất hiện lỗi cho biết tôi cần ID. Sau một giờ kéo tóc và nhiều máy chủ khởi động lại, bằng cách nào đó nó đã tự sửa. Tôi không biết ... nhưng nếu người khác trải nghiệm điều đó, hãy tiếp tục cố gắng!
Erik Trautman

@countbeing - không có vấn đề gì mà tôi biết, tôi chỉ không thích có các tuyến đường không được sử dụng hoặc dựa vào việc đặt hàng.
Nathan Long

1
"Câu trả lời thực tế" không hoàn thành tiêu diệt tuyến đường nếu nó được chuyển hướng từ bên trong bộ điều khiển phát minh. Hành vi mặc định vẫn sẽ định tuyến bạn đến đường dẫn đăng ký nếu bạn nhấn tuyến đường GET như thế nào https://example.com/users/. Xem câu trả lời của tôi dưới đây.
lacostenycoder

1
Lỗ hổng bảo mật! "Câu trả lời thực tế" được hiển thị chỉ thoát khỏi hình thức đăng ký, nó KHÔNG thoát khỏi tuyến đường POST thực sự tạo ra người dùng.
Eric Terry

Câu trả lời:


54

Tôi đã cố gắng để làm điều này là tốt, nhưng một chủ đề trên nhóm google nghĩ ra đã ngăn cản tôi tìm kiếm một giải pháp thực sự sạch sẽ.

Tôi sẽ trích dẫn Jose Valim (người duy trì Devise):

Không có một lựa chọn đơn giản. Bạn có thể cung cấp một bản vá hoặc sử dụng: Skip =>: có thể đăng ký và chỉ thêm các tuyến bạn muốn.

Câu hỏi ban đầu là:

Có cách nào tốt để xóa một tuyến đường cụ thể (tuyến đường xóa) khỏi Rails không?


4
Hoàn toàn chính xác. Trên thực tế, tôi đã đề xuất một bản vá và anh ta lịch sự từ chối: "Hôm nay, bạn có thể bỏ qua toàn bộ bộ điều khiển. Nó không tối ưu về mặt sử dụng, nhưng thiết lập các tuyến cho toàn bộ bộ điều khiển theo cách thủ công là khá đơn giản. Tôi tin rằng việc loại trừ các tuyến theo tên sẽ làm cho mã tạo tuyến trở nên phức tạp hơn (vì nó đã có) bởi vì chúng tôi sẽ không thể sử dụng trình trợ giúp Rails (như tài nguyên, tài nguyên và bạn bè) ". github.com/plataformatec/devise/issues/ Kẻ
Nathan Long

2
Tôi không biết liệu đây có phải là trường hợp khi câu trả lời này ban đầu được viết không, nhưng đoạn mã trong trích dẫn từ José là sai. Trong Devise 3.4.1 thì :skip => :registrationskhông :skip => :registerable.
GMA

89

bạn có thể làm điều này trong mô hình của bạn

# typical devise setup in User.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

thay đổi nó thành:

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable

chú ý rằng biểu tượng :registerableđã bị xóa

Đó là nó, không có gì khác là bắt buộc. Tất cả các tuyến đường và liên kết đến trang đăng ký cũng bị xóa một cách kỳ diệu.


21
Thật không may, điều này cũng loại bỏ các tuyến đường edit_user_registration, mà tôi cần. Như tôi đã nói, "họ vẫn có thể chỉnh sửa hồ sơ của họ."
Nathan Long

1
À, OK, tôi thường làm tròn điều này bằng cách cài đặt rails_admin gem, cho phép người dùng đi đến localhost:3000/adminnơi họ có thể chỉnh sửa tài khoản của mình, ngay cả khi đã xóa đối tượng có thể tháo rời. Nếu đó không phải là một giải pháp khả thi, thì hãy xem CanCan cho phép bạn quy định ai có thể và không thể truy cập tài nguyên. Tôi có xu hướng thêm các vai trò như 'quản trị viên' hoặc 'người điều hành' và khóa mọi người khác khỏi các trang đăng nhập.
stephenmurdoch

28
Sử dụng một phần quản trị (được xây dựng để cho phép chỉnh sửa các bản ghi tùy ý) để cung cấp cách cho người dùng chỉnh sửa hồ sơ của riêng họ là ý tưởng tồi tệ nhất mà tôi đã nghe trong một thời gian dài. Xin đừng ai làm điều này
Jeremy

Làm thế nào để vô hiệu hóa sign_introng sản xuất?
WM

30

Tôi gặp vấn đề tương tự đã cố gắng xóa đường dẫn devise_invitable để tạomới :

trước:

 devise_for :users

tuyến cào

accept_user_invitation GET    /users/invitation/accept(.:format)           devise/invitations#edit
       user_invitation POST   /users/invitation(.:format)                  devise/invitations#create
   new_user_invitation GET    /users/invitation/new(.:format)              devise/invitations#new
                       PUT    /users/invitation(.:format)                  devise/invitations#update

sau

devise_for :users , :skip => 'invitation'
devise_scope :user do
  get "/users/invitation/accept", :to => "devise/invitations#edit",   :as => 'accept_user_invitation'
  put "/users/invitation",        :to => "devise/invitations#update", :as => nil
end

tuyến cào

accept_user_invitation GET    /users/invitation/accept(.:format)                 devise/invitations#edit
                       PUT    /users/invitation(.:format)                        devise/invitations#update

lưu ý 1 phạm vi phát minh https://github.com/plataformatec/devise#configuring-routes

lưu ý 2 Tôi đang áp dụng nó trên devise_invitable nhưng nó sẽ hoạt động với mọi tính năng có thể phát triển *

Lưu ý quan trọng: thấy rằng devise_scope là trên người dùng không phải người dùng ? đúng rồi, coi chừng này! Nó có thể gây ra nhiều đau đớn cho bạn vấn đề này:

Started GET "/users/invitation/accept?invitation_token=xxxxxxx" for 127.0.0.1 
Processing by Devise::InvitationsController#edit as HTML
  Parameters: {"invitation_token"=>"6Fy5CgFHtjWfjsCyr3hG"}
 [Devise] Could not find devise mapping for path "/users/invitation/accept?  invitation_token=6Fy5CgFHtjWfjsCyr3hG".
This may happen for two reasons:

1) You forgot to wrap your route inside the scope block. For example:

  devise_scope :user do
     match "/some/route" => "some_devise_controller"
  end

 2) You are testing a Devise controller bypassing the router.
   If so, you can explicitly tell Devise which mapping to use:

    @request.env["devise.mapping"] = Devise.mappings[:user]

Cảm ơn chính xác những gì tôi đang tìm kiếm. Đối với những người khác sử dụng giải pháp này, tôi đã phải thêm /: id vào định nghĩa tuyến đường đặt.
Giăng

21

Tôi tìm thấy một bài viết tương tự như bài này và muốn chia sẻ một câu trả lời mà @chrisnicola đã đưa ra. Trong bài đăng, họ đã cố gắng chỉ chặn đăng ký của người dùng trong quá trình sản xuất.

Bạn cũng có thể sửa đổi bộ điều khiển đăng ký. Bạn có thể sử dụng một cái gì đó như thế này:

Trong "ứng dụng / bộ điều khiển / đăng ký_controll.rb"

class RegistrationsController < Devise::RegistrationsController
  def new
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end

  def create
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end
end

Điều này sẽ ghi đè lên bộ điều khiển của devise và sử dụng các phương thức trên thay thế. Họ đã thêm các tin nhắn flash trong trường hợp ai đó đã đưa nó vào trang đăng nhập. Bạn cũng có thể thay đổi chuyển hướng đến bất kỳ con đường nào bạn muốn.

Ngoài ra trong "config / Rout.rb", bạn có thể thêm phần này:

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

Để nó như thế này sẽ cho phép bạn sử dụng tiêu chuẩn chỉnh sửa hồ sơ của bạn. Nếu bạn muốn bạn vẫn có thể ghi đè tùy chọn chỉnh sửa hồ sơ bằng cách bao gồm

  def update
  end

trong "ứng dụng / bộ điều khiển / đăng ký_controll.rb"


13

Đây là một câu hỏi cũ - nhưng gần đây tôi đã giải quyết vấn đề tương tự và đưa ra một giải pháp thanh lịch hơn nhiều so với:

devise_for :users, :skip => [:registrations] 
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

Và nó cung cấp tên mặc định cho các tuyến đã đặt tên (như cancel_user_registration) mà không quá dài dòng.

devise_for :users, skip: [:registrations]

# Recreates the Devise registrations routes
# They act on a singular user (the signed in user)
# Add the actions you want in 'only:'
resource :users,
    only: [:edit, :update, :destroy],
    controller: 'devise/registrations',
    as: :user_registration do
  get 'cancel'
end

rake routes đầu ra với các mô-đun phát minh mặc định:

                  Prefix Verb   URI Pattern                    Controller#Action
        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)        devise/registrations#cancel
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
       user_registration PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy

12

Bạn có thể ghi đè "devise_scope" bằng cách đặt nó trước "devise_for".

devise_scope :user do
  get "/users/sign_up",  :to => "sites#index"
end

devise_for :users

Không chắc đây có phải là cách tốt nhất không nhưng đây là giải pháp của tôi, vì nó chỉ chuyển hướng trở lại trang đăng nhập.


1
Tôi đã thực hiện một cách tiếp cận tương tự, nhưng cũng muốn URL thay đổi, vì vậy đã đi với `get" / users / sign_up ",: to => redirect (" / ")`
dinjas

Vì vậy, giải quyết đơn giản và dễ dàng nhất. Nhưng giải quyết này có một vấn đề một phút. Địa chỉ vẫn còn. Nếu bạn nhập /users/sign_upsau đó bạn sẽ có quyền truy cập vào các sites#indexkhông sign_upnhưng địa chỉ vẫn được duy trì /users/sign_up.
Chim cánh cụt

5

Tôi thích câu trả lời của @ max , nhưng khi thử sử dụng, tôi đã gặp phải một lỗi do devise_mappingkhông.

Tôi đã sửa đổi giải pháp của anh ấy một chút để giải quyết vấn đề. Nó yêu cầu gói cuộc gọi vào resourcebên trong devise_scope.

devise_for :users, skip: [:registrations]

devise_scope :user do
  resource :users,
           only: [:edit, :update, :destroy],
           controller: 'devise/registrations',
           as: :user_registration do
    get 'cancel'
  end
end

Lưu ý rằng devise_scopemong đợi số ít :usertrong khi resourcemong đợi số nhiều :users.


4

Làm điều này trong tuyến.rb

devise_for :users, :controllers => {:registrations => "registrations"}, :skip => [:registrations]
  as :user do
    get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
    put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

  devise_scope :user do
    get "/sign_in",  :to => "devise/sessions#new"
    get "/sign_up",  :to => "devise/registrations#new"
  end

bây giờ bạn sẽ gặp lỗi trong khi bạn đăng nhập trang để sửa lỗi. Thực hiện thay đổi này trong: app / lượt xem / nghĩ ra / chia sẻ / _links.erb

<% if  request.path != "/sign_in" %>
    <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
        <%= link_to "Sign up", new_registration_path(resource_name) %><br />
    <% end -%>
<% end %>

Điều này làm việc cho tôi (tôi chỉ sử dụng khối devise_foraskhối) và tôi phải loại bỏ :registerabletrong mô hình.
dusan

3

Tôi đã thấy điều này hoạt động tốt mà không gây rối với các tuyến đường hoặc thêm các phương thức điều khiển ứng dụng. Cách tiếp cận của tôi là ghi đè phương thức phát minh. Thêm điều này vào app/controllers/devise/registrations_controller.rb Tôi đã bỏ qua các phương pháp khác cho ngắn gọn.

class Devise::RegistrationsController < DeviseController
  ...
  # GET /resource/sign_up
  def new
    redirect_to root_path
  end
  ....
end

Ngoài ra, để xóa ảo tưởng rằng đường dẫn này vẫn có thể truy cập được từ các chế độ xem khác, bạn cũng có thể muốn xóa mã này khỏi app/views/devise/shared/_links.erb

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>

2

Đối với những người khác trong trường hợp của tôi.
Với devise (3.5.2).
Tôi đã xóa thành công các tuyến đường để đăng ký, nhưng vẫn giữ các tuyến đường để chỉnh sửa hồ sơ, với mã sau đây.

#routes.rb
devise_for :users, skip: [:registrations]
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put '/users(.:format)' => 'devise/registrations#update', as: 'user_registration'
  patch '/users(.:format)' => 'devise/registrations#update'
end

1

Đây là con đường hơi khác tôi đã đi. Nó làm cho nó để bạn không phải ghi đè lên devise/shared/_links.html.erbxem.

Trong app/models/user.rb:

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable

Trong config/routes.rb:

devise_for :users
devise_scope :user do
  put 'users' => 'devise/registrations#update', as: 'user_registration'
  get 'users/edit' => 'devise/registrations#edit', as: 'edit_user_registration'
  delete 'users' => 'devise/registrations#destroy', as: 'registration'
end

Trước:

$ rake routes | grep 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)                     devise/registrations#cancel
          user_registration POST   /users(.:format)                            devise/registrations#create
      new_user_registration GET    /users/sign_up(.:format)                    devise/registrations#new
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
                            PATCH  /users(.:format)                            devise/registrations#update
                            PUT    /users(.:format)                            devise/registrations#update
                            DELETE /users(.:format)                            devise/registrations#destroy

Sau:

$ rake routes | grep 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
          user_registration PUT    /users(.:format)                            devise/registrations#update
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
               registration DELETE /users(.:format)                            devise/registrations#destroy

Nếu bạn không muốn có các tuyến dự phòng, hãy bỏ qua tất cả các tuyến mặc định, tức làdevise_for :users, skip: :all
elquimista

0

Tôi đã có cùng một vấn đề và tôi thấy đó là một thực tế xấu để chuyển hướng người dùng từ trang đăng ký. Vì vậy, giải pháp của tôi về cơ bản là không sử dụng :registrable.

Những gì tôi đã làm là tạo một trang tương tự như chỉnh sửa chi tiết người dùng trông giống như:

<%= form_tag(update_user_update_path, method: :post) do %>  
    <br>
    <%= label_tag(:currPassword, 'Current password:') %> <%= password_field_tag(:currPassword) %> <br>
    <%= label_tag(:newPassword, 'New password:') %> <%= password_field_tag(:newPassword) %> <br>
    <%= label_tag(:newPasswordConfirm, 'Confirm new password:') %> <%= password_field_tag(:newPasswordConfirm) %> <br>
    <%= submit_tag('Update') %>
<% end %>

Vì vậy, biểu mẫu này gửi đến một điểm cuối bài mới cập nhật mật khẩu, trông giống như:

  def update
    currPass = params['currPassword']
    newPass1 = params['newPassword']
    newPass2 = params['newPasswordConfirm']
    currentUserParams = Hash.new()
    currentUserParams[:current_password] = currPass
    currentUserParams[:password] = newPass1
    currentUserParams[:password_confirmation] = newPass2
    @result = current_user.update_with_password(currentUserParams)
  end

Sau này, bạn có thể sử dụng @resulttrong chế độ xem của mình để cho người dùng biết mật khẩu có được cập nhật hay không.


0

Bằng cách thay đổi các tuyến đường, có một loạt các vấn đề khác đi kèm với điều đó. Phương pháp đơn giản nhất tôi đã tìm thấy là làm như sau.

ApplicationController < ActionController::Base
  before_action :dont_allow_user_self_registration

  private

  def dont_allow_user_self_registration
    if ['devise/registrations','devise_invitable/registrations'].include?(params[:controller]) && ['new','create'].include?(params[:action])
      redirect_to root_path
    end
  end
end

Hoạt động, nhưng bạn có thực sự muốn chạy phương thức này trên từng hành động không?
lacostenycoder

-7

Bạn có thể sửa đổi deviseđá quý chính nó. Đầu tiên, chạy lệnh này để tìm vị trí đã cài đặt bằng cách sử dụng:

gem which devise

Hãy giả sử đường dẫn là: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Sau đó đi đến

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsvà chỉnh sửa routes.rbtrong thư mục đó. Có một phương thức gọi là def devise_registration(mapping, controllers)bạn có thể sửa đổi để thoát khỏi hành động mới. Bạn cũng có thể loại bỏ hoàn toàn ánh xạ chodevise_registration


+1 cho một đề xuất thay thế, nhưng việc bỏ một viên đá quý dường như ít được mong muốn hơn so với việc đưa một số mã khó xử vào các tuyến đường của tôi.
Nathan Long

4
trong thực tế nói chung điều này là lớn Không-Không! bạn nên giữ đá quý như chúng và nếu bạn cần thay đổi thứ gì đó chỉ cần con khỉ vá chúng
tương

Tôi đồng ý với bạn trong trường hợp này, nhưng nói chung tôi không nghĩ bạn nên tránh thực hiện các thay đổi đối với các thư viện / đá quý mà bạn sử dụng như là một thay thế cho mã vá khỉ ở một loạt các địa điểm khác nhau. Khả năng tạo khuôn thư viện theo nhu cầu của bạn là một trong những điểm cộng lớn của việc sử dụng mã nguồn mở IMO.
Ankit Soni

Nếu bạn định sửa đổi viên đá quý, ít nhất là rẽ nhánh nó và hướng Gemfile của bạn vào viên ngọc đã vá của bạn (ví dụ như trên github). Tôi đã làm điều này nhiều lần. Quá trình là: fork gem, nhân bản ngã ba của bạn cục bộ, khỉ vá phiên bản địa phương của bạn, đẩy vào repo từ xa của bạn và trỏ Gemfile vào nó. (tức là gem 'devise', github: 'yourusername/devise', branch: "master")
lacostenycoder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.