¿Cómo elimino la ruta de Devise para registrarme?

147

Estoy usando Devise en una aplicación Rails 3, pero en este caso, un usuario debe ser creado por un usuario existente, que determina qué permisos tendrá.

Debido a esto, quiero:

  • Para eliminar la ruta para que los usuarios se registren .
  • Para seguir permitiendo a los usuarios editar sus perfiles (cambiar la dirección de correo electrónico y la contraseña) después de haberse registrado

¿Cómo puedo hacer esto?

Actualmente, estoy eliminando efectivamente esta ruta colocando lo siguiente antes devise_for :users:

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

Eso funciona, pero me imagino que hay una mejor manera, ¿verdad?

Actualizar

Como dijo Benoit Garret, la mejor solución en mi caso es omitir la creación de las rutas de registros en masa y simplemente crear las que realmente quiero.

Para hacer eso, primero corrí rake routes, luego usé el resultado para volver a crear los que quería. El resultado final fue este:

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

Tenga en cuenta que:

  • Todavia tengo :registerableen mi Usermodelo
  • devise/registrations maneja la actualización de correo electrónico y contraseña
  • La actualización de otros atributos de usuario (permisos, etc.) es manejada por un controlador diferente

Respuesta real:

Elimine la ruta para los caminos de diseño predeterminados; es decir:

devise_for :users, path_names: {
  sign_up: ''
}
Nathan Long
fuente
44
De hecho, creo que su solución original fue mucho más simple y clara. ¿Hay algún problema real con la seguridad?
contrarrestar el
Por alguna razón, su solución actualizada seguía arrojando un error que decía que necesitaba la ID. Después de una hora de arrancarse el cabello y muchos reinicios de muchos servidores, de alguna manera se arregló. No tengo idea ... pero si alguien más experimenta eso, ¡sigue intentándolo!
Erik Trautman
@counterbeing: no hay ningún problema que yo sepa, simplemente no me gustaba tener rutas no utilizadas o depender de pedidos.
Nathan Long
1
La "respuesta real" no se completa, elimina la ruta si se redirige desde dentro del controlador del dispositivo. El comportamiento predeterminado todavía lo enrutará a la ruta de registro si presiona GET route like https://example.com/users/. Vea mi respuesta a continuación.
lacostenycoder
1
Falla de seguridad! La "Respuesta real" que se muestra solo elimina el formulario de registro, NO elimina la ruta POST que realmente crea el usuario.
Eric Terry

Respuestas:

54

Traté de hacer esto también, pero un hilo en el ingenioso grupo de Google me disuadió de buscar una solución realmente limpia.

Citaré a José Valim (el encargado del diseño):

No hay una opción directa. Puede proporcionar un parche o usar: skip =>: registrable y agregar solo las rutas que desee.

La pregunta original fue:

¿Hay alguna buena manera de eliminar una ruta específica (la ruta de eliminación) de Rails?

Benoit Garret
fuente
44
Muy correcto De hecho, le propuse un parche y él cortésmente lo rechazó: "Hoy en día, puede omitir todo el controlador. No es óptimo en términos de uso, pero configurar las rutas para todo el controlador manualmente es bastante sencillo. Creo que excluir las rutas por nombre solo hará que el código de generación de rutas sea más complicado (de lo que ya lo es) porque no podremos usar los ayudantes de Rails (como recursos, recursos y amigos) ". github.com/plataformatec/devise/issues/…
Nathan Long
2
No sé si este fue el caso cuando esta respuesta se escribió originalmente, pero el código en la cita de José es incorrecto. En Diseñar 3.4.1 es :skip => :registrationsno :skip => :registerable.
GMA
89

puedes hacer esto en tu modelo

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

cámbielo a:

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

observe que el símbolo :registerablefue eliminado

Eso es todo, no se requiere nada más. Todas las rutas y enlaces a la página de registro también se eliminan mágicamente.

stephenmurdoch
fuente
21
Desafortunadamente, esto también elimina la ruta a la edit_user_registrationque necesito. Como dije, "aún deberían poder editar sus perfiles".
Nathan Long
1
Ahh, OK, bueno, normalmente soluciono esto instalando rails_admin gem, que permite a los usuarios ir a localhost:3000/admindonde pueden editar su cuenta, incluso con el objeto resistente eliminado. Si esa no es una solución viable, eche un vistazo a CanCan, que le permite estipular quién puede y quién no puede acceder a un recurso. Tiendo a agregar roles como 'admin' o 'moderador' y bloquear a todos los demás fuera de las páginas de registro.
stephenmurdoch
28
Usar una sección de administración (que está diseñada para permitir la edición de registros arbitrarios) para proporcionar a los usuarios una forma de editar sus propios perfiles es la peor idea que he escuchado en mucho tiempo. Por favor, nadie haga esto
Jeremy
¿Cómo deshabilitar sign_inen producción?
WM
30

Tuve un problema similar al intentar eliminar las rutas de devise_invitable para crear y nuevas :

antes de:

 devise_for :users

rutas de rastrillo

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

después

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

rutas de rastrillo

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

nota 1 idear alcance https://github.com/plataformatec/devise#configuring-routes

nota 2 Lo estoy aplicando en devise_invitable pero funcionará con cualquier función de * ideable

Nota importante: ¿ ve que devise_scope está en el usuario, no en los usuarios ? eso es correcto, ¡cuidado con esto! Puede causar mucho dolor al causarle este problema:

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]
equivalente8
fuente
Gracias exactamente lo que estaba buscando. Para otros que usan esta solución, tuve que agregar /: id a la definición de ruta de colocación.
John
21

Encontré otra publicación similar a esta y quería compartir una respuesta que @chrisnicola dio. En la publicación, intentaban bloquear solo los registros de usuarios durante la producción.

También puede modificar el controlador de registros. Puedes usar algo como esto:

En "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

Esto anulará el controlador del dispositivo y utilizará los métodos anteriores en su lugar. Agregaron mensajes flash en caso de que alguien de alguna manera llegara a la página de registro. También debe poder cambiar la redirección a cualquier ruta que desee.

También en "config / routes.rb" puede agregar esto:

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

Dejarlo así le permitirá utilizar el dispositivo estándar para editar su perfil. Si lo desea, puede anular la opción de editar perfil incluyendo

  def update
  end

en "app / controllers / registrations_controller.rb"

Daniel
fuente
13

Esta es una vieja pregunta, pero recientemente tuve que resolver el mismo problema y se me ocurrió una solución que es mucho más elegante que:

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

Y proporciona los nombres predeterminados para las rutas nombradas (como cancel_user_registration) sin ser excesivamente detallado.

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 salida con los módulos de diseño predeterminados:

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

Puede anular el "devise_scope" colocándolo antes del "devise_for".

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

devise_for :users

No estoy seguro de si esta es la mejor manera, pero es mi solución actualmente, ya que solo redirige a la página de inicio de sesión.

Medianoche
fuente
1
Tomé un enfoque similar, pero quería que la URL también cambiara, así que fui con `get" / users / sign_up ",: to => redirect (" / ")`
dinjas
Tan simple y fácil de resolver. Pero esta resolución tiene un problema de un minuto. La dirección se mantuvo. Si ingresa, /users/sign_upentonces tendrá acceso a la dirección pero sites#indexno sign_upse mantendrá /users/sign_up.
Penguin
5

Me gustó la respuesta de @ max , pero cuando traté de usarla me encontré con un error debido a que devise_mappingera nula.

Modifiqué su solución ligeramente a una que parece abordar el problema. Se requiere envolver la llamada al resourceinterior 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

Tenga en cuenta que devise_scopeespera el singular :usermientras que resourceespera el plural :users.

dvanoni
fuente
4

Haga esto en 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

obtendrá un error ahora mientras viene a la página de inicio de sesión, para solucionarlo. Haga este cambio en: 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
fuente
Esto funcionó para mí (solo usé el devise_fory el asbloque) y tuve que eliminarlo :registerableen el modelo.
dusan
3

He encontrado que esto funciona bien sin alterar las rutas o agregar métodos de controlador de aplicaciones. Mi enfoque es anular el método de diseño. Agregue esto a app/controllers/devise/registrations_controller.rb He omitido los otros métodos por brevedad.

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

También para eliminar la ilusión de que esta ruta aún es accesible desde otras vistas, es posible que también desee eliminar este código de 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
fuente
2

Para otros en mi caso.
Con devise (3.5.2).
Eliminé con éxito las rutas para registrarme, pero guardé las para editar el perfil, con el siguiente código.

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

Aquí está la ruta ligeramente diferente que fui. Lo hace para que no tenga que anular eldevise/shared/_links.html.erb vista.

En app/models/user.rb:

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

En 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

Antes de:

$ 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

Después:

$ 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
fuente
Si no desea tener rutas redundantes, omita todas las rutas predeterminadas, es decirdevise_for :users, skip: :all
elquimista el
0

Tuve el mismo problema y me pareció una mala práctica redirigir a los usuarios desde la página de registro. Entonces, mi solución es básicamente no usar :registrablenada.

Lo que hice fue crear una página similar, como editar detalles del usuario, que se veía así:

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

Por lo tanto, este formulario se envía a un nuevo punto final de publicación que actualiza la contraseña, que se ve así:

  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

Más adelante, puede usar el @resulten su vista para decirle al usuario si la contraseña se actualiza o no.

Sarp Kaya
fuente
0

Al cambiar las rutas, hay muchos otros problemas que vienen con eso. El método más fácil que he encontrado es hacer lo siguiente.

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
fuente
Funciona, pero ¿realmente quieres ejecutar este método en cada acción?
lacostenycoder
-7

Podrías modificar la devisegema misma. Primero, ejecute este comando para encontrar la ubicación instalada de uso:

gem which devise

Supongamos que el camino es: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Luego ve a

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsy editar routes.rben ese directorio. Hay un método llamado def devise_registration(mapping, controllers)que puede modificar para deshacerse de la nueva acción. También puede eliminar completamente las asignaciones paradevise_registration

Ankit Soni
fuente
+1 para una sugerencia alternativa, pero bifurcar una gema me parece menos deseable que poner un código incómodo en mis rutas.
Nathan Long
44
En la práctica general, este es un gran No-No! debes mantener las gemas tal como están y si necesitas cambiar algo, solo el parche de mono
equivalente8
Estoy de acuerdo con usted en este caso, pero en general no creo que deba evitar hacer cambios en las bibliotecas / gemas que usa como alternativa al código de parches de mono en muchos lugares diferentes. La capacidad de moldear una biblioteca a sus necesidades es una de las grandes ventajas de usar el código fuente abierto IMO.
Ankit Soni
Si va a modificar la gema, al menos bifurque y apunte su Gemfile a la gema parchada de su mono (en github, por ejemplo). Lo he hecho en varias ocasiones. El proceso es: bifurcar gema, clonar su bifurcación localmente, mono parchear su versión local, empujar a su repositorio remoto y apuntar Gemfile a él. (es decir gem 'devise', github: 'yourusername/devise', branch: "master")
lacostenycoder