Настройка маршрутизации: есть ли способ удалить маршрут из Rails.application.routes?
devise_for
создает маршруты, включая маршрут DELETE, который мы хотим удалить, а devise_for
не поддерживает параметр :except
или :only
.
Как удалить маршрут из Rails.application.routes
? Либо в блоке draw
, либо после?
Ниже приведены сведения об ошибке, которая была причиной, по которой нам нужно было удалить маршрут.
-
мы выдавали запрос DELETE к пользовательскому действию контроллера UJS
-
в действии контроллера мы снимали то, что хотели, а затем перенаправляли 302. Это была плохая идея, и с тех пор мы исправили ее, вернув несколько JSON.
- некоторые клиенты, получив 302, выдадут новый запрос DELETE для перенаправления, который направляется на маршрут удаления Devise! Таким образом, непреднамеренно удаляя человека! Хлоп. Мы предполагали, что это будет ПОЛУЧИТЬ. Плохое предположение.
Эта ошибка исправлена, но тем не менее я хочу удалить маршрут.
Вот что я сделал в конце, что было предложено победителем в его цитате из Хосе Валима:
В config/routes.rb
я добавил это выше вызова devise_for
, который устанавливает остальные мои маршруты 'people'
:
delete '/person', :to => 'people#destroy'
Затем в моем существующем people_controller.rb
я добавил метод no-op:
def destroy
render :nothing => true
end
Я все еще немного раздражен, что нет простого способа просто удалить маршрут из RouteSet. Кроме того, маршрут delete
по-прежнему существует для контроллера разработки, но он не будет вызван, потому что rails ищет первое совпадение в config/routes.rb
и возвращает его.
Ответы
Ответ 1
Вот что говорит Хосе Валим (автор проекта) по теме:
Невозможно удалить маршруты по отдельности. Или вы используете: пропустите удалите все и нарисуйте те, которые вам нужны вручную, или вы перезапишите это маршрутов, определяя маршрут к одному и тому же пути сначала в вашей конфигурации / routes.rb
Итак, короткий ответ на ваш вопрос - нет, вы не можете удалить этот маршрут. Вы можете, конечно, попробовать сделать что-то вроде исправления метода devise_for, но это будет несколько связанное с этим мероприятие (день или несколько усилий). Я бы просто использовал опцию: skip, а затем реализовал маршруты, которые вы хотите для этого контроллера, и оставьте тот, который у вас нет.
Ответ 2
Да, любопытное. Вы можете полностью перезаписать разработанные контроллеры и написать свои собственные (наследуя Devise, если необходимо). Эта страница wiki может служить в качестве ориентира.
Изменить
Почему я сказал что-то вроде:)
Переопределение сеансов с использованием:
devise_for :users, :controllers => { :sessions => 'custom_devise/sessions'}, :skip => [:sessions] do
get 'sign_in' => 'custom_devise/sessions#new', :as => :new_user_session
post 'sign_in' => 'custom_devise/sessions#create', :as => :user_session
end
предоставит вам только два маршрута [: get,: post], но не: destroy
new_user_session GET /sign_in(.:format) {:controller=>"custom_devise/sessions", :action=>"new"}
user_session POST /sign_in(.:format) {:controller=>"custom_devise/sessions", :action=>"create"}
Таким образом, вы пропускаете маршрут уничтожения/удаления. Теперь в контроллере вы можете пойти:
class SessionsController < Devise::SessionsController
def new
super
end
def create
super
end
end
Теперь вы можете повторить процесс регистрации, паролей и разблокировок.
Второе редактирование
А, да, есть еще один, более простой способ. Вы можете вручную создавать маршруты (документация), используя devise_scope, также известный как "как" без переопределения:
as :user do
get "sign_in", :to => "devise/sessions#new"
post "sign_in", :to => "devise/sessions#create"
...
end
дает:
sign_in GET /sign_in(.:format) {:controller=>"devise/sessions", :action=>"new"}
POST /sign_in(.:format) {:controller=>"devise/sessions", :action=>"create"}
Третий редактор
Кроме того, вы можете перезаписать часть Devise, отвечающую за создание этих маршрутов (только для использования в приложениях, которые не будут разрабатывать "уничтожить" маршрут), создав инициализатор:
module ActionDispatch::Routing
extend ActionDispatch::Routing
class Mapper
protected
def devise_session(mapping, controllers) #:nodoc:
resource :session, :only => [], :controller => controllers[:sessions], :path => "" do
get :new, :path => mapping.path_names[:sign_in], :as => "new"
post :create, :path => mapping.path_names[:sign_in]
end
end
def devise_registration(mapping, controllers) #:nodoc:
path_names = {
:new => mapping.path_names[:sign_up],
:cancel => mapping.path_names[:cancel]
}
resource :registration, :only => [:new, :create, :edit, :update], :path => mapping.path_names[:registration],
:path_names => path_names, :controller => controllers[:registrations] do
get :cancel
end
end
end
end
Обратите внимание, что это исправление удаляет все пути уничтожения, используемые в Devise (в "сеансах" и "регистрации" есть только два) и является исправлением только для этого конкретного случая.
Кроме того,
Вы также можете добавить: кроме опции для маршрутов. Чтобы сделать это, вы должны добавить метод devise_for
(скопировать его из оригинала и изменить в соответствии с вашими пожеланиями) классу Mapper, чтобы он отправил [: except] член опций для вышеупомянутых (в коде) частных методов. Затем вы должны изменить их для добавления маршрутов на основе условий.
Самый быстрый, грязный способ - добавить @scope [: except] = options [: except], а затем изменить частные методы, чтобы исключить хеш (если вы решили иметь мелкозернистый контроль маршрута, например: :except => {:sessions => [:destroy]}
, что делает :skip
устаревшим) или массив (если вы хотите удалить это конкретное действие со всех маршрутов, например: :except => [:destroy]
), перед добавлением маршрута будет проверено.
Во всяком случае, есть много способов добиться того, что вам нужно. Это зависит от вас, чтобы выбрать тот, который, по вашему мнению, лучше всего подходит.
Ответ 3
Фактически devise_for
поддерживает :skip
и :only
, например (docs):
devise_for :user, :skip => :registration
Это будет пропускать все маршруты контроллера регистрации, а не отдельно. Затем вы можете реализовать маршруты, которые вам нужны. Это кажется более чистым, чем удаление маршрута после факта.
UPDATE:
Еще одно возможное решение - использовать функцию Rails расширенные ограничения для полного блокирования нежелательного маршрута:
# config/routes.rb
constraints lambda {|req| req.url =~ /users/ && req.delete? ? false : true} do
devise_for :users
end
Вот сообщение об использовании lambdas для ограничений маршрута. Объект запроса объясняется здесь. Это может быть самым простым решением.
Ответ 4
Я нашел простое решение с Devise 4.2.0 и Rails 5.0.1. Я думаю, что это будет работать с Rails 4, и я не уверен в более старых версиях Devise.
Создайте инициализатор, переопределяющий помощники маршрута devise_*
. Примерами являются devise_session
, devise_password
, devise_confirmation
, devise_unlock
и devise_registration
. Проверьте источник .
Убедитесь, что инициализатор загружен после инициализатора Devise, указав имя файла более крупным буквенно-цифровым значением.
Например, Devise создает маршрут подтверждения: :new
, :create
и :show
. Мне нужно только действие :create
.
# config/initializers/devise_harden.rb
module ActionDispatch::Routing
class Mapper
# Override devise confirmation route setup, as we want to limit it to :create
def devise_confirmation(mapping, controllers)
resource :confirmation, only: [:create],
path: mapping.path_names[:confirmation], controller: controllers[:confirmations]
end
end
end
Теперь POST /auth/confirmation
- единственная настройка маршрута для подтверждения.