Як видалити маршрут розробки для реєстрації?


147

Я використовую Devise в додатку Rails 3, але в цьому випадку користувача повинен створити існуючий користувач, який визначає, які дозволи він матиме.

Через це я хочу:

  • Щоб видалити маршрут, щоб користувачі могли підписатися .
  • Щоб дозволити користувачам редагувати свої профілі (змінити адресу електронної пошти та пароль) після їх реєстрації

Як я можу це зробити?

На даний момент я ефективно видаляю цей маршрут, розміщуючи таке devise_for :users:

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

Це працює, але я думаю, що є кращий спосіб, правда?

Оновлення

Як сказав Бенуа Гаррет, найкраще рішення в моєму випадку - пропустити масове створення маршрутів реєстрації та просто створити ті, які я насправді хочу.

Для цього я спершу запустив rake routes, а потім використав результат для того, щоб відтворити ті, які я хотів. Кінцевим результатом було таке:

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

Зауважте, що:

  • Я до сих пір :registerableв моїй Userмоделі
  • devise/registrations обробляє оновлення електронної пошти та пароля
  • Оновлення інших атрибутів користувача - дозволів тощо - обробляє інший контролер

Фактична відповідь:

Видаліть маршрут за замовчуванням Розробити контури; тобто:

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

4
Я фактично думаю, що ваше оригінальне рішення було набагато простішим і зрозумілішим. Чи є якась реальна проблема щодо безпеки безпеки?
протидія

Чомусь ваше оновлене рішення продовжувало кидати помилку, кажучи, що мені потрібен ідентифікатор. Після години витягування волосся та багатьох серверних перезавантажень воно якось виправилося. Я поняття не маю ... але якщо хтось ще відчуває це, продовжуйте намагатися!
Ерік Траутман

@counterbeing - жодна проблема, про яку я знаю, мені просто не сподобалося мати невикористані маршрути або покладатися на замовлення.
Натан Лонг

1
"Фактична відповідь" не завершує введення маршруту, якщо він перенаправлений на внутрішній диспетчер. Поведінка за замовчуванням все одно буде спрямовувати вас до шляху реєстрації, якщо ви натиснете GET route like https://example.com/users/. Дивіться мою відповідь нижче.
лакостенікодер

1
Порушення безпеки! "Фактична відповідь", яка відображається лише позбутися форми реєстрації, вона НЕ позбавляється від маршруту POST, який фактично створює користувача.
Ерік Террі

Відповіді:


54

Я також спробував це зробити, але нитка в створеній групі google відвернула мене від пошуку дійсно чистого рішення.

Я цитую Жозе Валіма (розробника):

Немає прямого варіанту. Ви можете надати виправлення або використати: skip =>: реєструвати та додати лише потрібні маршрути.

Первісне питання:

Чи є якийсь хороший спосіб видалити певний маршрут (маршрут видалення) з Rails?


4
Цілком правильно. Насправді я запропонував патч, і він ввічливо відмовився: "Сьогодні ви можете пропустити весь контролер. Це не оптимально з точки зору використання, але налаштування маршрутів для цілого контролера вручну досить просто". Я вважаю, що виключення маршрутів за назвою просто збільшить код генерації маршрутів (ніж це вже є), оскільки ми не зможемо використовувати помічники Rails (як-от ресурс, ресурси та друзі) ". github.com/plataformatec/devise/isissue/…
Натан Лонг

2
Я не знаю, чи це було так, коли ця відповідь була написана спочатку, але код у цитаті від Хосе помиляється. У Devise 3.4.1 це :skip => :registrationsне так :skip => :registerable.
GMA

89

ви можете зробити це у своїй моделі

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

змінити його на:

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

зауважте, що символ :registerableбуло видалено

Це все, нічого іншого не потрібно. Усі маршрути та посилання на сторінку реєстрації теж магічно видаляються.


21
На жаль, це також видаляє маршрут edit_user_registration, який мені потрібен. Як я вже сказав, "вони все ще мають змогу редагувати свої профілі".
Натан Лонг

1
Ага, гаразд, добре, що я зазвичай обійшов це, встановивши дорогу gil rails_admin , яка дозволяє користувачам зайти туди, localhost:3000/adminде вони можуть редагувати свій акаунт, навіть якщо видалений стійкий об’єкт. Якщо це не є життєздатним рішенням, то подивіться на CanCan, який дозволяє вам визначити, хто може і не може отримати доступ до ресурсу. Я схильний додавати такі ролі, як "адміністратор" або "модератор", і блокую всіх інших із сторінок реєстрації.
stephenmurdoch

28
Використання секції адміністратора (яка створена для редагування довільних записів), щоб надати користувачам спосіб редагувати власні профілі - це найгірша ідея, яку я чув за тривалий час. Нікого цього не робіть
Джеремі

Як відключити sign_inвиробництво?
WM

30

У мене була подібна проблема, яка намагалася видалити devise_invitable шляхи для створення та нового :

перед:

 devise_for :users

рейкові маршрути

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

після

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

рейкові маршрути

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

Примітка 1 розробити сферу https://github.com/plataformatec/devise#configuring-routes

Примітка 2 Я застосовую його на devise_invitable, але він буде працювати з будь-якою функцією devise *

Важлива примітка: бачите, що devise_scope призначений для користувачів, а не користувачів ? це правильно, стежте за цим! Це може заподіяти багато болю, доставляючи вам цю проблему:

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]

Дякую саме тому, що я шукав. Для інших, хто використовує це рішення, мені довелося додати /: id до визначення put route.
Джон

21

Я знайшов ще одну публікацію, схожу на цю, і хотів поділитися відповіддю, яку дала @chrisnicola. У публікації вони намагалися блокувати реєстрацію користувачів лише під час виробництва.

Ви також можете змінити контролер реєстрації. Ви можете використовувати щось подібне:

В "застосунку / контролери / реєстрації_контроль.рб"

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

Це дозволить змінити контролер пристрою і використовувати замість нього вищевказані методи. Вони додали флеш-повідомлення на випадок, коли хтось якось потрапив на сторінку реєстрації. Ви також повинні мати можливість змінити переадресацію на будь-який шлях, який вам подобається.

Також у "config / route.rb" ви можете додати це:

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

Залишаючи це так, ви зможете скористатися стандартним редактором редагування свого профілю. Якщо ви хочете, ви все одно можете змінити параметр редагування профілю, включивши його

  def update
  end

у "застосунку / контролери / реєстрації_контроль.рб"


13

Це давнє питання - але я нещодавно вирішив те саме питання і придумав рішення, яке набагато елегантніше, ніж:

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

І він дає за замовчуванням імена для названих маршрутів (як cancel_user_registration), не надмірно багатослівних.

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 вихід з модулями розробки за замовчуванням:

                  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

Ви можете змінити "devise_scope", поставивши його перед "devise_for".

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

devise_for :users

Не впевнений, що це найкращий спосіб, але це моє рішення на даний момент, оскільки він просто переспрямовує назад на сторінку входу.


1
Я взяв подібний підхід, але хотів, щоб і URL-адреса змінилася, тому пішла з `get '/ users / sign_up",: to => redirect ("/") `
dinjas

Так просто і найпростіше рішення. Але це рішення має одну хвилину. Залишилася адреса. Якщо ви ввійдете , /users/sign_upто ви будете доступ до sites#indexНЕ sign_upтільки адреса все ще залишається /users/sign_up.
Пінгвін

5

Мені сподобалося @ Макс відповіді , але при спробі використовувати його я зіткнувся з помилкою з - за devise_mappingбудучи нуль.

Я трохи змінив його рішення на той, який, здається, вирішує проблему. Це вимагало завершити дзвінок resourceвсередину 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

Зауважимо, що devise_scopeочікує однини:user тоді як resourceочікує множини :users.


4

Робіть це в 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

ви отримаєте помилку зараз, коли прийдете на сторінку входу, щоб виправити її. Внесіть цю зміну в: 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 %>

Це працює для мене (я тільки використовував devise_forі в asблок) , і мені довелося видалити :registerableв моделі.
дусан

3

Я виявив, що це добре працює, не возившись з маршрутами або додаючи методи контролера додатків. Мій підхід полягає в тому, щоб перекрити метод розробки. Додайте до цього, app/controllers/devise/registrations_controller.rb я пропустив інші методи стислості.

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

Щоб також видалити ілюзію, що цей шлях все ще доступний для інших поглядів, ви також можете видалити цей код з 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

Для інших у моєму випадку.
З devise (3.5.2).
Я успішно видалив маршрути для реєстрації, але зберіг їх для редагування профілю із наступним кодом.

#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

Ось трохи інший маршрут, яким я пішов. Це робить це так, що вам не доведеться перекриватиdevise/shared/_links.html.erb подання.

В app/models/user.rb:

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

В 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

Перед:

$ 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

Після:

$ 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

Якщо ви не хочете мати зайвих маршрутів, пропустіть усі маршрути за замовчуванням, тобтоdevise_for :users, skip: :all
elquimista

0

У мене був такий самий випуск, і я вважав трохи поганою практикою перенаправляти користувачів із сторінки реєстрації. Тож моє рішення - це взагалі не використання :registrable.

Що я зробив, це створити подібну сторінку, як редагувати деталі користувача, яка виглядала так:

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

Таким чином, ця форма надсилається в новій точці після публікації, яка оновлює пароль, виглядає так:

  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

Пізніше ви можете скористатись @resultвашим переглядом, щоб повідомити користувачеві, оновлено чи ні пароль.


0

Змінюючи маршрути, виникає ціла купа інших проблем, які виникають із цим. Найпростіший метод, який я знайшов, - це зробити наступне.

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

Працює, але чи справді ви хочете запустити цей метод на кожній дії?
лакостенікодер

-7

Ви можете змінити deviseсамоцвіт. Спочатку запустіть цю команду, щоб знайти встановлене місце використання:

gem which devise

Припустимо, шлях такий: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Потім переходьте до

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsі редагуйте routes.rbв цьому каталозі. Існує метод, званий def devise_registration(mapping, controllers)який ви можете змінити, щоб позбутися від нової дії. Ви також можете повністю видалити відображення дляdevise_registration


+1 за альтернативну пропозицію, але роздрібнювати дорогоцінний камінь мені здається менш бажаним, ніж додавати якийсь незручний код у мої маршрути.
Натан Лонг

4
в загальній практиці це великий Ні-Ні! ви повинні зберігати дорогоцінні камені такими, якими вони є, і якщо вам потрібно щось змінити, просто мавпа виправить їх
рівнозначно8

Я погоджуюся з вами в цьому випадку, але в цілому я не думаю, що вам слід ухилятися від внесення змін до бібліотек / дорогоцінних каменів, які ви використовуєте як альтернативу коду патч-мавпи в купі різних місць. Можливість формувати бібліотеку під ваші потреби - один із великих плюсів використання IMO з відкритим кодом.
Анкіт Соні

Якщо ви збираєтеся змінити дорогоцінний камінь, принаймні роздвойте його та вкажіть свій Gemfile на ваш дорогоцінний дорогоцінний камінь (наприклад, на github). Я робив це кілька разів. Процес: вилка gem, клоніруйте вилку локально, мавпа виправляє локальну версію, натискайте на віддалене репо і вкажіть на нього Gemfile. (тобто gem 'devise', github: 'yourusername/devise', branch: "master")
лакостенікодер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.