Jak usunąć trasę Devise, aby się zarejestrować?

147

Używam Devise w aplikacji Rails 3, ale w tym przypadku użytkownik musi być utworzony przez istniejącego użytkownika, który określa, jakie uprawnienia będzie miał.

Z tego powodu chcę:

  • Aby usunąć trasę dla użytkowników do rejestracji .
  • Aby nadal zezwalać użytkownikom na edytowanie swoich profili (zmiana adresu e-mail i hasła) po zarejestrowaniu się

W jaki sposób mogę to zrobić?

Obecnie skutecznie usuwam tę trasę, umieszczając przed devise_for :users:

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

To działa, ale wyobrażam sobie, że jest lepszy sposób, prawda?

Aktualizacja

Jak powiedział Benoit Garret, najlepszym rozwiązaniem w moim przypadku jest pominięcie masowego tworzenia tras rejestracji i utworzenie tych, które faktycznie chcę.

Aby to zrobić, najpierw uruchomiłem rake routes, a następnie wykorzystałem dane wyjściowe do odtworzenia tych, które chciałem. Wynik końcowy był następujący:

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

Zauważ, że:

  • Nadal mam :registerablew swoim Usermodelu
  • devise/registrations obsługuje aktualizację adresu e-mail i hasła
  • Aktualizowanie innych atrybutów użytkownika - uprawnień itp. - jest obsługiwane przez inny kontroler

Rzeczywista odpowiedź:

Usuń trasę dla domyślnych ścieżek Devise; to znaczy:

devise_for :users, path_names: {
  sign_up: ''
}
Nathan Long
źródło
4
Właściwie myślę, że Twoje oryginalne rozwiązanie było znacznie prostsze i bardziej przejrzyste. Czy jest z tym jakiś prawdziwy problem pod względem bezpieczeństwa?
przeciwstawienie
Z jakiegoś powodu Twoje zaktualizowane rozwiązanie wyświetlało błąd informujący, że potrzebuję identyfikatora. Po godzinie wyrywania włosów i wielu restartach serwerów, jakoś się naprawił. Nie mam pojęcia ... ale jeśli ktoś inny tego doświadczy, próbuj dalej!
Erik Trautman
@ Counterbeing - żaden problem, o którym wiem, po prostu nie lubiłem mieć niewykorzystanych tras lub polegać na zamówieniach.
Nathan Long
1
„Rzeczywista odpowiedź” nie powoduje zakończenia trasy, jeśli jest przekierowywana z poziomu kontrolera urządzenia. Domyślne zachowanie nadal przekieruje Cię do ścieżki rejestracji, jeśli naciśniesz opcję GET route jak https://example.com/users/. Zobacz moją odpowiedź poniżej.
lacostenycoder,
1
Luka w zabezpieczeniach! „Rzeczywista odpowiedź”, która jest wyświetlana, usuwa jedynie formularz rejestracyjny, NIE usuwa trasy POST, która faktycznie tworzy użytkownika.
Eric Terry

Odpowiedzi:

54

Ja też próbowałem to zrobić, ale wątek w opracowanej przeze mnie grupie Google odstraszył mnie od szukania naprawdę czystego rozwiązania.

Zacytuję José Valima (opiekuna Devise):

Nie ma prostej opcji. Możesz dostarczyć łatkę lub użyć: skip =>: registerable i dodać tylko te trasy, które chcesz.

Pierwotne pytanie brzmiało:

Czy jest jakiś dobry sposób na usunięcie określonej trasy (trasy usuwania) z Railsów?

Benoit Garret
źródło
4
Całkiem poprawnie. Właściwie zaproponowałem łatkę, a on grzecznie odmówił: „Dziś można pominąć cały kontroler. Nie jest to optymalne z punktu widzenia użytkowania, ale ręczne ustawienie tras dla całego kontrolera jest całkiem proste. Uważam, że wykluczanie tras nazwa po prostu uczyni kod generowania tras bardziej skomplikowanym (niż jest), ponieważ nie będziemy mogli używać pomocników Rails (takich jak zasoby, zasoby i przyjaciele) ". github.com/plataformatec/devise/issues/…
Nathan Long
2
Nie wiem, czy tak było, gdy pierwotnie napisano tę odpowiedź, ale kod w cytacie José jest błędny. W Devise 3.4.1 tak :skip => :registrationsnie jest :skip => :registerable.
GMA
89

możesz to zrobić w swoim modelu

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

zmień to na:

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

zauważ, że symbol :registerablezostał usunięty

To wszystko, nic więcej nie jest wymagane. Wszystkie trasy i linki do strony rejestracji są również magicznie usuwane.

stephenmurdoch
źródło
21
Niestety to też usuwa trasę do edit_user_registrationktórej potrzebuję. Jak powiedziałem, „nadal powinni mieć możliwość edytowania swoich profili”.
Nathan Long,
1
Ahh, OK, cóż, zwykle omijam to, instalując gem rails_admin , który pozwala użytkownikom przejść do localhost:3000/adminmiejsca, w którym mogą edytować swoje konto, nawet po usunięciu obiektu odpornego na działanie. Jeśli nie jest to wykonalne rozwiązanie, spójrz na CanCan, który pozwala określić, kto może, a kto nie może uzyskać dostępu do zasobu. Mam tendencję do dodawania ról, takich jak „administrator” lub „moderator”, i blokowania wszystkim pozostałym osobom dostępu do stron rejestracji.
stephenmurdoch
28
Korzystanie z sekcji administratora (która jest zbudowana, aby umożliwić edycję dowolnych rekordów), aby zapewnić użytkownikom możliwość edycji własnych profili, to najgorszy pomysł, jaki słyszałem od dłuższego czasu. Proszę, nikt tego nie robi
Jeremy
Jak wyłączyć sign_inw produkcji?
WM
30

Miałem podobny problem, próbując usunąć ścieżki devise_invitable dla tworzenia i nowego :

przed:

 devise_for :users

trasy rake

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

po

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

trasy rake

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

uwaga 1 zakres opracowania https://github.com/plataformatec/devise#configuring-routes

uwaga 2 Stosuję go na devise_invitable, ale będzie działać z każdą funkcją devise * w stanie

Ważna uwaga: czy widzisz, że devise_scope dotyczy użytkowników, a nie użytkowników ? zgadza się, uważaj na to! Może powodować wiele bólu, powodując ten problem:

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]
odpowiednik 8
źródło
Dzięki dokładnie za to, czego szukałem. Dla innych, którzy używają tego rozwiązania, musiałem dołączyć /: id do definicji trasy put.
John
21

Znalazłem inny post podobny do tego i chciałem podzielić się odpowiedzią, której udzielił @chrisnicola. W poście próbowali zablokować rejestrację użytkowników tylko podczas produkcji.

Możesz także zmodyfikować kontroler rejestracji. Możesz użyć czegoś takiego:

W „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

Spowoduje to zastąpienie kontrolera devise i zamiast tego użyje powyższych metod. Dodali wiadomości flash na wypadek, gdyby ktoś w jakiś sposób znalazł się na stronie sign_up. Powinieneś także móc zmienić przekierowanie na dowolną ścieżkę.

Również w „config / tours.rb” możesz dodać to:

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

Pozostawienie tego w ten sposób pozwoli Ci korzystać ze standardowego urządzenia do edycji swojego profilu. Jeśli chcesz, nadal możesz zastąpić opcję edycji profilu, włączając

  def update
  end

w „app / controllers / registrations_controller.rb”

Daniel
źródło
13

To stare pytanie - ale ostatnio rozwiązałem ten sam problem i znalazłem rozwiązanie, które jest znacznie bardziej eleganckie niż:

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

I podaje domyślne nazwy nazwanych tras (np. cancel_user_registration), Nie będąc nadmiernie rozwlekłymi.

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 wyjście z domyślnymi modułami devise:

                  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
max
źródło
12

Możesz nadpisać „devise_scope”, umieszczając ją przed „devise_for”.

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

devise_for :users

Nie jestem pewien, czy to najlepszy sposób, ale obecnie jest to moje rozwiązanie, ponieważ po prostu przekierowuje z powrotem do strony logowania.

Północ
źródło
1
Podjąłem podobne podejście, ale chciałem, aby adres URL również się zmienił, więc poszedłem z `get" / users / sign_up ",: to => przekierowanie (" / ")`
dinjas
Tak proste i najłatwiejsze rozwiązanie. Ale to rozwiązanie ma jeden minutowy problem. Adres pozostał. Jeśli wejdziesz /users/sign_up, będziesz mieć dostęp do sites#indexnie, sign_upale adres nadal pozostanie /users/sign_up.
Penguin
5

Lubiłem @ Maxa odpowiedzią , ale kiedy próbuje go używać wpadłem błędu z powodu devise_mappingbędącego zera.

Zmodyfikowałem nieco jego rozwiązanie, aby rozwiązać ten problem. Wymagało to skierowania rozmowy do resourceśrodka 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

Zauważ, że devise_scopeoczekuje liczby pojedynczej, :userpodczas gdy resourceoczekuje liczby mnogiej :users.

dvanoni
źródło
4

Zrób to w route.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

pojawi się błąd podczas logowania się na stronie, aby go naprawić. Zrób tę zmianę w: 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
źródło
To zadziałało dla mnie (użyłem tylko devise_fori asbloku) i musiałem usunąć :registerablew modelu.
dusan,
3

Zauważyłem, że to działa dobrze bez majstrowania przy trasach lub dodawania metod kontrolera aplikacji. Moje podejście polega na zastąpieniu metody opracowanej. Dodaj to do app/controllers/devise/registrations_controller.rb Pominąłem inne metody dla zwięzłości.

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

Aby usunąć złudzenie, że ta ścieżka jest nadal dostępna z innych widoków, możesz również chcieć usunąć ten kod 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
źródło
2

Dla innych w moim przypadku.
Z devise (3.5.2).
Pomyślnie usunąłem trasy do rejestracji, ale zachowałem te do edycji profilu, z następującym kodem.

#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
źródło
1

Oto nieco inna trasa, którą poszedłem. Dzięki temu nie musisz przesłonić devise/shared/_links.html.erbwidoku.

W app/models/user.rb:

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

W 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

Przed:

$ 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

Po:

$ 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
źródło
Jeśli nie chcesz mieć zbędnych tras, pomiń wszystkie domyślne trasy, czylidevise_for :users, skip: :all
elquimista
0

Miałem ten sam problem i przekierowywanie użytkowników ze strony rejestracji było trochę złą praktyką. Więc moje rozwiązanie w zasadzie :registrablew ogóle nie używa .

To, co zrobiłem, to utworzenie podobnej strony, takiej jak edycja danych użytkownika, która wyglądała następująco:

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

Więc ten formularz jest przesyłany do nowego punktu końcowego postu, który aktualizuje hasło, które wygląda następująco:

  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

Później możesz użyć @resultw swoim widoku, aby poinformować użytkownika, czy hasło zostało zaktualizowane, czy nie.

Sarp Kaya
źródło
0

Zmiana tras wiąże się z całą masą innych problemów. Najłatwiejszą metodą, jaką znalazłem, jest wykonanie następujących czynności.

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
źródło
Działa, ale czy naprawdę chcesz uruchamiać tę metodę przy każdej akcji?
lacostenycoder,
-7

Możesz zmodyfikować devisesam klejnot. Najpierw uruchom to polecenie, aby znaleźć zainstalowaną lokalizację za pomocą:

gem which devise

Załóżmy, że ścieżka to: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Następnie idź do

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsi edytuj routes.rbw tym katalogu. Istnieje metoda o nazwie, def devise_registration(mapping, controllers)którą możesz zmodyfikować, aby pozbyć się nowej akcji. Możesz także całkowicie usunąć mapowania dladevise_registration

Ankit Soni
źródło
+1 za alternatywną sugestię, ale rozwidlenie klejnotu wydaje mi się mniej pożądane niż umieszczanie niezręcznego kodu na moich trasach.
Nathan Long
4
w praktyce jest to duże Nie-Nie! powinieneś zachować klejnoty takimi, jakie są, a jeśli chcesz coś zmienić, po prostu małpuj je
odpowiednik8
Zgadzam się z tobą w tym przypadku, ale generalnie nie uważam, że powinieneś unikać zmian w bibliotekach / klejnotach, których używasz jako alternatywy dla małpiego łatania kodu w wielu różnych miejscach. Możliwość dostosowania biblioteki do własnych potrzeb to jedna z największych zalet korzystania z otwartego kodu źródłowego IMO.
Ankit Soni,
Jeśli zamierzasz zmodyfikować klejnot, przynajmniej rozwidl go i skieruj swój plik Gemfile na klejnot z łatą małpy (na przykład na githubie). Robiłem to przy kilku okazjach. Proces to: fork gem, klonuj widelec lokalnie, małpa łata lokalną wersję, pchnij do zdalnego repozytorium i skieruj do niego Gemfile. (tj. gem 'devise', github: 'yourusername/devise', branch: "master")
lacostenycoder