Wie entferne ich die Devise-Route, um mich anzumelden?

147

Ich verwende Devise in einer Rails 3-App. In diesem Fall muss ein Benutzer von einem vorhandenen Benutzer erstellt werden, der bestimmt, über welche Berechtigungen er verfügt.

Aus diesem Grund möchte ich:

  • So entfernen Sie die Route, auf der sich Benutzer anmelden können .
  • Um immer noch zu erlauben , Benutzer zu bearbeiten ihre Profile (ändern E - Mail - Adresse und Passwort) , nachdem sie haben unterschrieben

Wie kann ich das machen?

Derzeit entferne ich diese Route effektiv, indem ich Folgendes vorstelle devise_for :users:

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

Das funktioniert, aber ich stelle mir vor, es gibt einen besseren Weg, oder?

Aktualisieren

Wie Benoit Garret sagte, besteht die beste Lösung in meinem Fall darin, das Erstellen der Registrierungsrouten in Massen zu überspringen und nur die zu erstellen, die ich tatsächlich möchte.

Dazu habe ich zuerst ausgeführt rake routesund dann die Ausgabe verwendet, um die gewünschten neu zu erstellen. Das Endergebnis war folgendes:

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

Beachten Sie, dass:

  • Ich habe noch :registerablein meinem UserModell
  • devise/registrations kümmert sich um die Aktualisierung von E-Mail und Passwort
  • Das Aktualisieren anderer Benutzerattribute - Berechtigungen usw. - wird von einem anderen Controller durchgeführt

Aktuelle Antwort:

Entfernen Sie die Route für die Standardpfade. dh:

devise_for :users, path_names: {
  sign_up: ''
}
Nathan Long
quelle
4
Ich denke tatsächlich, dass Ihre ursprüngliche Lösung viel einfacher und klarer war. Gibt es ein echtes Sicherheitsproblem?
counterbeing
Aus irgendeinem Grund gab Ihre aktualisierte Lösung immer wieder den Fehler aus, dass ich die ID benötigte. Nach einer Stunde des Haarziehens und vielen, vielen Neustarts des Servers hat es sich irgendwie selbst repariert. Ich habe keine Ahnung ... aber wenn jemand anderes das erlebt, versuchen Sie es weiter!
Erik Trautman
@counterbeing - kein Problem, das ich kenne, ich mochte es einfach nicht, unbenutzte Routen zu haben oder mich auf die Bestellung zu verlassen.
Nathan Long
1
"Tatsächliche Antwort" beendet die Route nicht vollständig, wenn sie von einem Devise Controller aus umgeleitet wird. Das Standardverhalten leitet Sie weiterhin zum Anmeldepfad weiter, wenn Sie auf GET route like klicken https://example.com/users/. Siehe meine Antwort unten.
Lacostenycoder
1
Sicherheitslücke! Die angezeigte "Tatsächliche Antwort" entfernt nur das Anmeldeformular. Die POST-Route, die den Benutzer tatsächlich erstellt, wird NICHT entfernt.
Eric Terry

Antworten:

54

Ich habe auch versucht, dies zu tun, aber ein Thread über die Google-Gruppe mich davon abgehalten, nach einer wirklich sauberen Lösung zu suchen.

Ich zitiere José Valim (den Devise-Betreuer):

Es gibt keine einfache Option. Sie können entweder einen Patch bereitstellen oder Folgendes verwenden: skip =>: registerable und nur die gewünschten Routen hinzufügen.

Die ursprüngliche Frage war:

Gibt es eine gute Möglichkeit, eine bestimmte Route (die Löschroute) von Rails zu entfernen?

Benoit Garret
quelle
4
Ganz richtig. Tatsächlich schlug ich einen Patch vor und er lehnte höflich ab: "Heute können Sie den gesamten Controller überspringen. Es ist nicht optimal in Bezug auf die Nutzung, aber das manuelle Einrichten der Routen für den gesamten Controller ist ziemlich einfach. Ich glaube, dass das Ausschließen von Routen Mit Namen wird der Code für die Routengenerierung nur komplizierter (als er bereits ist), da wir keine Rails-Helfer (wie Ressourcen, Ressourcen und Freunde) verwenden können. " github.com/plataformatec/devise/issues/…
Nathan Long
2
Ich weiß nicht, ob dies der Fall war, als diese Antwort ursprünglich geschrieben wurde, aber der Code im Zitat von José ist falsch. In Devise 3.4.1 ist dies :skip => :registrationsnicht der Fall :skip => :registerable.
GMA
89

Sie können dies in Ihrem Modell tun

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

ändere es in:

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

Beachten Sie, dass das Symbol :registerableentfernt wurde

Das war's, sonst ist nichts erforderlich. Alle Routen und Links zur Registrierungsseite werden ebenfalls auf magische Weise entfernt.

stephenmurdoch
quelle
21
Leider entfernt dies auch den Weg zu edit_user_registration, den ich brauche. Wie gesagt: "Sie sollten weiterhin in der Lage sein, ihre Profile zu bearbeiten."
Nathan Long
1
Ahh, OK, normalerweise gehe ich um dieses Problem herum , indem ich das Juwel rails_admin installiere , mit dem Benutzer dorthin gehen können, localhost:3000/adminwo sie ihr Konto bearbeiten können, selbst wenn das widerstandsfähige Objekt entfernt wurde. Wenn dies keine praktikable Lösung ist, werfen Sie einen Blick auf CanCan, mit dem Sie festlegen können, wer auf eine Ressource zugreifen kann und wer nicht. Ich neige dazu, Rollen wie "admin" oder "moderator" hinzuzufügen und alle anderen von den Anmeldeseiten auszuschließen.
Stephenmurdoch
28
Die schlechteste Idee, die ich seit langem gehört habe, ist die Verwendung eines Admin-Abschnitts (der die Bearbeitung beliebiger Datensätze ermöglicht), um Benutzern die Möglichkeit zu geben, ihre eigenen Profile zu bearbeiten. Bitte niemand tut dies
Jeremy
Wie sign_inin der Produktion deaktivieren ?
WM
30

Ich hatte ein ähnliches Problem versucht, devise_invitable Pfade für create und new zu entfernen :

Vor:

 devise_for :users

Rechenrouten

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

nach dem

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

Rechenrouten

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

Anmerkung 1: Gültigkeitsbereich https://github.com/plataformatec/devise#configuring-routes

note 2 Ich wende es auf devise_invitable an, aber es funktioniert mit jeder devise * -fähigen Funktion

Wichtiger Hinweis: Sehen Sie, dass devise_scope für Benutzer und nicht für Benutzer bestimmt ist ? das ist richtig, pass auf! Es kann viele Schmerzen verursachen, die Ihnen dieses Problem verursachen:

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]
Äquivalent8
quelle
Vielen Dank genau das, wonach ich gesucht habe. Für andere, die diese Lösung verwenden, musste ich /: id an die Definition der Put-Route anhängen.
John
21

Ich fand einen ähnlichen Beitrag und wollte eine Antwort teilen, die @chrisnicola gab. In der Post wurde versucht, Benutzeranmeldungen nur während der Produktion zu blockieren.

Sie können auch den Registrierungscontroller ändern. Sie können so etwas verwenden:

In "app / controller / 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

Dadurch wird der Controller des Geräts überschrieben und stattdessen die oben genannten Methoden verwendet. Sie haben Flash-Nachrichten hinzugefügt, falls jemand es irgendwie auf die Seite sign_up geschafft hat. Sie sollten auch in der Lage sein, die Umleitung in einen beliebigen Pfad zu ändern.

Auch in "config / route.rb" können Sie Folgendes hinzufügen:

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

Wenn Sie dies so belassen, können Sie das Standardgerät verwenden, um Ihr Profil zu bearbeiten. Wenn Sie möchten, können Sie die Option zum Bearbeiten des Profils weiterhin durch Einfügen überschreiben

  def update
  end

in der "app / controller / registrations_controller.rb"

Daniel
quelle
13

Dies ist eine alte Frage - aber ich hatte kürzlich das gleiche Problem gelöst und eine Lösung gefunden, die weitaus eleganter ist als:

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

Und es gibt die Standardnamen für die benannten Routen (wie cancel_user_registration) an, ohne übermäßig ausführlich zu sein.

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 Ausgabe mit den Standardmodulen:

                  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
quelle
12

Sie können das "devise_scope" überschreiben, indem Sie es vor das "devise_for" stellen.

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

devise_for :users

Ich bin mir nicht sicher, ob dies der beste Weg ist, aber es ist derzeit meine Lösung, da es nur zur Anmeldeseite zurückleitet.

Mitternacht
quelle
1
Ich verfolgte einen ähnlichen Ansatz, wollte aber, dass sich auch die URL ändert, also ging ich zu "get" / users / sign_up ": to => redirect (" / ")"
dinjas
So einfach und einfach zu lösen. Diese Lösung hat jedoch ein einminütiges Problem. Die Adresse bleibt erhalten. Wenn Sie eingeben, erhalten /users/sign_upSie Zugriff auf die sites#indexnicht, sign_upaber die Adresse bleibt weiterhin erhalten /users/sign_up.
Pinguin
5

Ich mochte die Antwort von @ max , aber als ich versuchte, sie zu verwenden, stieß ich auf einen Fehler aufgrund vondevise_mapping ich null war.

Ich habe seine Lösung leicht dahingehend geändert, dass sie das Problem zu lösen scheint. Der Anruf musste nach resourceinnen verpackt werden 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

Beachten Sie, devise_scopedass der Singular erwartet wird, :userwährend resourceder Plural erwartet wird :users.

Dvanoni
quelle
4

Tun Sie dies in 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

Sie erhalten jetzt eine Fehlermeldung, während Sie zur Anmeldeseite kommen, um sie zu beheben. Nehmen Sie diese Änderung vor in: 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
quelle
Dies funktionierte für mich (ich habe nur den devise_forund den asBlock verwendet) und ich musste ihn :registerableim Modell entfernen .
Dusan
3

Ich habe festgestellt, dass dies gut funktioniert, ohne mit Routen herumzuspielen oder Anwendungscontrollermethoden hinzuzufügen. Mein Ansatz ist es, die Entwurfsmethode zu überschreiben. Fügen Sie dies hinzu, app/controllers/devise/registrations_controller.rb ich habe die anderen Methoden der Kürze halber weggelassen.

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

Um die Illusion zu beseitigen, dass dieser Pfad aus anderen Ansichten noch erreichbar ist, möchten Sie möglicherweise auch diesen Code entfernen 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
quelle
2

Für andere in meinem Fall.
Mit devise (3.5.2).
Ich habe die Routen zur Anmeldung erfolgreich entfernt, aber diejenigen zum Bearbeiten des Profils mit dem folgenden Code beibehalten.

#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
quelle
1

Hier ist der etwas andere Weg, den ich gegangen bin. Es macht es so, dass Sie das nicht überschreiben müssendevise/shared/_links.html.erb Ansicht .

In app/models/user.rb:

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

In 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

Vor:

$ 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

Nach dem:

$ 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
quelle
Wenn Sie keine redundanten Routen haben möchten, überspringen Sie alle Standardrouten, dhdevise_for :users, skip: :all
elquimista
0

Ich hatte das gleiche Problem und fand es etwas schlecht, Benutzer von der Registrierungsseite umzuleiten. Meine Lösung ist also im Grunde nicht zu verwenden:registrable .

Was ich getan habe, war, eine ähnliche Seite wie das Bearbeiten von Benutzerdetails zu erstellen, die wie folgt aussah:

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

Dieses Formular wird also an einen neuen Post-Endpunkt gesendet, der das Kennwort aktualisiert. Dies sieht folgendermaßen aus:

  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

Später können Sie das @resultin Ihrer Ansicht verwenden, um dem Benutzer mitzuteilen, ob das Kennwort aktualisiert wurde oder nicht.

Sarp Kaya
quelle
0

Durch das Ändern der Routen ergeben sich eine ganze Reihe weiterer Probleme. Die einfachste Methode, die ich gefunden habe, ist die folgende.

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
quelle
Funktioniert, aber möchten Sie diese Methode wirklich für jede einzelne Aktion ausführen?
Lacostenycoder
-7

Sie können den deviseEdelstein selbst ändern . Führen Sie zunächst diesen Befehl aus, um den installierten Speicherort für Folgendes zu ermitteln:

gem which devise

Nehmen wir an, der Pfad ist: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Dann geh zu

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsund routes.rbin diesem Verzeichnis bearbeiten . Es gibt eine Methode, def devise_registration(mapping, controllers)die Sie ändern können, um die neue Aktion zu entfernen. Sie können die Zuordnungen für auch vollständig entfernendevise_registration

Ankit Soni
quelle
+1 für einen alternativen Vorschlag, aber das Verzweigen eines Edelsteins scheint mir weniger wünschenswert, als einen unangenehmen Code in meine Routen einzufügen.
Nathan Long
4
In der allgemeinen Praxis ist dies ein großes Nein-Nein! Sie sollten Edelsteine ​​so lassen, wie sie sind, und wenn Sie etwas ändern müssen, flicken Sie sie einfach mit Affen
äquivalent8
In diesem Fall stimme ich Ihnen zu, aber im Allgemeinen sollten Sie sich nicht scheuen, Änderungen an Bibliotheken / Edelsteinen vorzunehmen, die Sie als Alternative zum Affen-Patching-Code an verschiedenen Orten verwenden. Die Möglichkeit, eine Bibliothek an Ihre Bedürfnisse anzupassen, ist einer der großen Vorteile der Verwendung von Open-Source-Code IMO.
Ankit Soni
Wenn Sie den Edelstein modifizieren möchten, geben Sie ihn zumindest auf und richten Sie Ihre Edelsteindatei auf Ihren mit Affen gepatchten Edelstein (z. B. auf Github). Ich habe das schon mehrmals gemacht. Der Prozess ist: Gabel Gem, klonen Sie Ihre Gabel lokal, Affen-Patch Ihre lokale Version, Push auf Ihr Remote-Repo und zeigen Sie Gemfile darauf. (dh gem 'devise', github: 'yourusername/devise', branch: "master")
Lacostenycoder