Bagaimana cara menghapus rute Rencanakan untuk mendaftar?

147

Saya menggunakan Devise dalam aplikasi Rails 3, tetapi dalam hal ini, pengguna harus dibuat oleh pengguna yang ada, yang menentukan izin apa yang akan ia miliki.

Karena itu, saya ingin:

  • Untuk menghapus rute bagi pengguna untuk mendaftar .
  • Agar pengguna tetap dapat mengedit profil mereka (mengubah alamat email dan kata sandi) setelah mereka mendaftar

Bagaimana saya bisa melakukan ini?

Saat ini, saya secara efektif menghapus rute ini dengan menempatkan yang berikut sebelumnya devise_for :users:

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

Itu berhasil, tapi saya membayangkan ada cara yang lebih baik, bukan?

Memperbarui

Seperti yang dikatakan Benoit Garret, solusi terbaik dalam kasus saya adalah tidak membuat rute registrasi secara massal dan hanya membuat yang saya inginkan.

Untuk melakukan itu, saya pertama berlari rake routes, kemudian menggunakan output untuk membuat kembali yang saya inginkan. Hasil akhirnya adalah ini:

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

Perhatikan bahwa:

  • Saya masih memiliki model :registerablesayaUser
  • devise/registrations menangani pembaruan email dan kata sandi
  • Memperbarui atribut pengguna lain - izin, dll - ditangani oleh pengontrol yang berbeda

Jawaban aktual:

Hapus rute untuk jalur Rencanakan default; yaitu:

devise_for :users, path_names: {
  sign_up: ''
}
Nathan Long
sumber
4
Saya benar-benar berpikir solusi awal Anda jauh lebih sederhana, dan jelas. Apakah ada masalah nyata dengan keamanannya?
counterbeing
Untuk beberapa alasan solusi Anda yang diperbarui terus melontarkan kesalahan yang mengatakan bahwa saya memerlukan ID. Setelah satu jam penarik rambut dan banyak lagi restart server, entah bagaimana caranya memperbaiki sendiri. Saya tidak tahu ... tetapi jika orang lain mengalaminya, teruslah mencoba!
Erik Trautman
@counterbeing - tidak ada masalah yang saya tahu, saya hanya tidak suka memiliki rute yang tidak digunakan atau mengandalkan memesan.
Nathan Long
1
"Jawaban Aktual" tidak sepenuhnya membunuh rute jika diarahkan ke dari dalam merancang pengontrol. Perilaku default masih akan merutekan Anda ke jalur pendaftaran jika Anda menekan tombol GET seperti https://example.com/users/. Lihat jawaban saya di bawah ini.
lacostenycoder
1
Cacat Keamanan! "Jawaban aktual" yang ditampilkan hanya menyingkirkan formulir pendaftaran, itu TIDAK menyingkirkan rute POST yang benar-benar membuat pengguna.
Eric Terry

Jawaban:

54

Saya mencoba melakukan ini juga, tetapi utas pada grup google yang dirancang membuat saya tidak mencari solusi yang benar-benar bersih.

Saya akan mengutip José Valim (pengelola Rancangan):

Tidak ada opsi lurus ke depan. Anda dapat memberikan tambalan atau menggunakan: skip =>: registerable dan hanya menambahkan rute yang Anda inginkan.

Pertanyaan aslinya adalah:

Apakah ada cara yang baik untuk menghapus rute tertentu (rute hapus) dari Rails?

Benoit Garret
sumber
4
Cukup benar. Bahkan, saya mengusulkan sebuah tambalan dan dia dengan sopan menolak: "Hari ini, Anda dapat melewati seluruh pengontrol. Ini tidak optimal dalam hal penggunaan, tetapi mengatur rute untuk seluruh pengontrol secara manual cukup mudah. ​​Saya percaya bahwa tidak termasuk rute dengan nama hanya akan membuat kode pembuatan rute lebih rumit (daripada yang sudah ada) karena kita tidak akan dapat menggunakan pembantu Rails (seperti sumber daya, sumber daya, dan teman) ". github.com/plataformatec/devise/issues/…
Nathan Long
2
Saya tidak tahu apakah ini masalahnya ketika jawaban ini awalnya ditulis, tetapi kode dalam kutipan dari José salah. Dalam Rancangan 3.4.1 :skip => :registrationstidak :skip => :registerable.
GMA
89

Anda dapat melakukan ini dalam model Anda

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

ubah ke:

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

perhatikan bahwa simbol :registerabletelah dihapus

Itu saja, tidak ada lagi yang diperlukan. Semua rute dan tautan ke halaman pendaftaran juga dihapus secara ajaib.

stephenmurdoch
sumber
21
Sayangnya, ini juga menghilangkan rute ke edit_user_registration, yang saya butuhkan. Seperti yang saya katakan, "mereka masih dapat mengedit profil mereka."
Nathan Long
1
Ahh, OK, well, biasanya saya menyelesaikan ini dengan menginstal rails_admin gem, yang memungkinkan pengguna pergi ke localhost:3000/admintempat mereka dapat mengedit akun mereka, bahkan dengan objek yang dapat disimpan ulang dihapus. Jika itu bukan solusi yang layak, maka lihatlah CanCan yang memungkinkan Anda menentukan siapa yang dapat dan tidak dapat mengakses sumber daya. Saya cenderung menambahkan peran seperti 'admin' atau 'moderator' dan mengunci orang lain dari halaman sign_up.
stephenmurdoch
28
Menggunakan bagian admin (yang dibangun untuk memungkinkan pengeditan catatan sewenang-wenang) untuk menyediakan cara bagi pengguna untuk mengedit profil mereka sendiri adalah ide terburuk yang pernah saya dengar dalam waktu yang lama. Tolong tidak ada yang melakukan ini
Jeremy
Bagaimana cara menonaktifkan sign_inproduksi?
WM
30

Saya memiliki masalah serupa yang mencoba menghapus jalur devise_invitable untuk buat dan baru :

sebelum:

 devise_for :users

rute menyapu

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

setelah

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

rute menyapu

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

note 1 merancang ruang lingkup https://github.com/plataformatec/devise#configuring-routes

note 2 Saya menerapkannya pada devise_invitable tetapi akan bekerja dengan semua fitur * yang mampu

Catatan penting: lihat bahwa devise_scope berada di pengguna bukan pengguna ? benar, hati-hati! Ini dapat menyebabkan banyak rasa sakit memberi Anda masalah ini:

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]
setara8
sumber
Terima kasih apa yang saya cari. Untuk orang lain yang menggunakan solusi ini, saya harus menambahkan /: id ke definisi rute put.
John
21

Saya menemukan posting lain yang mirip dengan yang ini dan ingin membagikan jawaban yang diberikan @chrisnicola. Dalam postingan itu mereka berusaha untuk hanya memblokir pendaftaran pengguna selama produksi.

Anda juga dapat memodifikasi pengontrol pendaftaran. Anda dapat menggunakan sesuatu seperti ini:

Di "app / controllers / registrations_controller.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

Ini akan menggantikan pengontrol devise dan menggunakan metode di atas sebagai gantinya. Mereka menambahkan pesan flash memetikan bahwa seseorang entah bagaimana berhasil masuk ke halaman sign_up. Anda juga harus dapat mengubah pengalihan ke jalur apa pun yang Anda suka.

Juga di "config / routes.rb" Anda dapat menambahkan ini:

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

Membiarkannya seperti ini akan memungkinkan Anda untuk menggunakan alat standar mengedit profil Anda. Jika mau, Anda masih dapat mengganti opsi edit profil dengan memasukkan

  def update
  end

di "app / controllers / registrations_controller.rb"

Daniel
sumber
13

Ini adalah pertanyaan lama - tetapi saya baru saja menyelesaikan masalah yang sama dan menemukan solusi yang jauh lebih elegan daripada:

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

Dan itu memberikan nama default untuk rute yang dinamai (seperti cancel_user_registration) tanpa terlalu banyak bertele-tele.

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 output dengan modul alat bawaan:

                  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
maks
sumber
12

Anda dapat mengganti "devise_scope" dengan menempatkannya di depan "devise_for".

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

devise_for :users

Tidak yakin apakah ini cara terbaik tetapi ini solusi saya saat ini, karena hanya akan diarahkan kembali ke halaman masuk.

Tengah malam
sumber
1
Saya mengambil pendekatan yang sama, tetapi ingin URL juga berubah, jadi lanjutkan dengan `get" / users / sign_up ",: to => redirect (" / ")`
dinjas
Solusi yang begitu sederhana dan termudah. Tetapi pemecahan ini memiliki masalah satu menit. Alamatnya tetap. Jika Anda masuk /users/sign_upmaka Anda akan dapat mengakses sites#indexnot sign_uptapi alamat tetap ada /users/sign_up.
Penguin
5

Saya menyukai jawaban @ max , tetapi ketika mencoba menggunakannya saya mengalami kesalahan karena devise_mappingtidak ada.

Saya memodifikasi solusinya sedikit ke yang tampaknya mengatasi masalah ini. Perlu membungkus panggilan ke resourcedalam 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

Perhatikan bahwa devise_scopemengharapkan bentuk tunggal :usersedangkan resourcemengharapkan bentuk jamak :users.

dvanoni
sumber
4

Lakukan ini di routes.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

Anda akan mendapatkan kesalahan sekarang saat Anda masuk ke halaman masuk, untuk memperbaikinya. Lakukan perubahan ini di: app / views / devise / shared / _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 %>
Syed
sumber
Ini bekerja untuk saya (saya hanya menggunakan devise_fordan asblok) dan aku harus menghapus :registerabledalam model.
dusan
3

Saya menemukan ini berfungsi dengan baik tanpa mengacaukan rute atau menambahkan metode pengontrol aplikasi. Pendekatan saya adalah mengganti metode merancang. Tambahkan ini ke app/controllers/devise/registrations_controller.rb saya telah menghilangkan metode lain untuk singkatnya.

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

Juga untuk menghapus ilusi bahwa jalur ini masih dapat dijangkau dari tampilan lain, Anda mungkin juga ingin menghapus kode ini app/views/devise/shared/_links.erb

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

Untuk orang lain dalam kasus saya.
Dengan devise (3.5.2).
Saya berhasil menghapus rute untuk mendaftar, tetapi tetap yang mengedit profil, dengan kode berikut.

#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
Micka
sumber
1

Inilah rute yang sedikit berbeda yang saya tempuh. Itu membuatnya sehingga Anda tidak perlu menimpa devise/shared/_links.html.erbtampilan.

Di app/models/user.rb:

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

Di 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

Sebelum:

$ 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

Setelah:

$ 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
bmaddy
sumber
Jika Anda tidak ingin memiliki rute yang redundan, lewati semua rute default, yaitudevise_for :users, skip: :all
elquimista
0

Saya memiliki masalah yang sama dan saya merasa agak buruk untuk mengarahkan pengguna dari halaman pendaftaran. Jadi solusi saya pada dasarnya tidak menggunakan :registrablesama sekali.

Apa yang saya lakukan adalah membuat halaman yang mirip seperti mengedit detail pengguna yang terlihat seperti:

<%= 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 %>

Jadi formulir ini mengirimkan ke titik akhir pos baru yang memperbarui kata sandi, yang terlihat seperti:

  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

Selanjutnya Anda dapat menggunakan @resultdalam tampilan Anda untuk memberi tahu pengguna apakah kata sandi diperbarui atau tidak.

Sarp Kaya
sumber
0

Dengan mengubah rute ada banyak masalah lain yang datang dengan itu. Metode termudah yang saya temukan adalah melakukan hal berikut.

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
Weston Ganger
sumber
Berhasil, tetapi apakah Anda benar-benar ingin menjalankan metode ini pada setiap tindakan?
lacostenycoder
-7

Anda dapat memodifikasi devisepermata itu sendiri. Pertama, jalankan perintah ini untuk menemukan lokasi terinstal menggunakan:

gem which devise

Misalkan jalannya adalah: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Lalu pergi ke

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsdan edit routes.rbdi direktori itu. Ada metode yang disebut def devise_registration(mapping, controllers)yang dapat Anda modifikasi untuk menyingkirkan tindakan baru. Anda juga dapat menghapus sepenuhnya pemetaan untukdevise_registration

Ankit Soni
sumber
Memberi +1 untuk saran alternatif, tetapi forking a gem tampaknya kurang diinginkan bagi saya daripada memasukkan beberapa kode aneh di rute saya.
Nathan Long
4
dalam praktik umum ini adalah besar. Anda harus menyimpan permata apa adanya dan jika Anda perlu mengubah sesuatu, cukup tambal monyet
setara 8
Saya setuju dengan Anda dalam hal ini, tetapi secara umum saya tidak berpikir Anda harus menghindar dari membuat perubahan ke perpustakaan / permata yang Anda gunakan sebagai alternatif untuk kode patch monyet di banyak tempat yang berbeda. Kemampuan untuk mencetak perpustakaan sesuai kebutuhan Anda adalah salah satu nilai tambah besar menggunakan kode sumber terbuka IMO.
Ankit Soni
Jika Anda akan memodifikasi permata, setidaknya garpu dan arahkan Gemfile Anda ke permata tambalan monyet Anda (pada github misalnya). Saya telah melakukan ini pada beberapa kesempatan. Prosesnya adalah: fork gem, kloning fork Anda secara lokal, monyet tempel versi lokal Anda, dorong ke repo jarak jauh Anda dan arahkan Gemfile ke sana. (ie gem 'devise', github: 'yourusername/devise', branch: "master")
lacostenycoder