Подтвердить что ты не робот

Настройка маршрутизации: есть ли способ удалить маршрут из 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 и возвращает его.

4b9b3361

Ответ 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 - единственная настройка маршрута для подтверждения.