Разработать маршрутизацию: есть ли способ удалить маршрут из Rails.application.routes? - PullRequest
19 голосов
/ 08 августа 2011

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 я добавил неоперативный метод:

def destroy
  render :nothing => true
end

Я все еще немного раздражен тем, что не существует простого способа просто удалить маршрут из RouteSet.Кроме того, маршрут delete все еще существует для контроллера devise, но он не будет вызван, потому что rails ищет первое совпадение в config/routes.rb и возвращает его.

Ответы [ 4 ]

12 голосов
/ 12 августа 2011

Вот что говорит Хосе Валим (автор устройства) по теме :

Невозможно удалить маршруты по отдельности. Или вы используете: перейти к удалите все и нарисуйте нужные вам вручную или перезапишите маршруты, определяя маршрут к тому же пути сначала в вашей конфигурации / routes.rb

Итак, краткий ответ на ваш вопрос - нет, вы не можете удалить этот маршрут. Конечно, вы можете попробовать сделать что-то вроде исправления метода devise_for, но это будет довольно сложным делом (день или несколько стоит усилий). Я бы просто использовал опцию: skip, затем реализовал маршруты, которые вы хотите для этого контроллера, и оставил бы тот, который вам не нужен.

8 голосов
/ 09 августа 2011

Да, вроде.Вы можете полностью переписать используемые контроллеры devise и написать свои собственные (наследуя Devise, если это необходимо). Эта вики-страница может служить ориентиром.

Редактировать

Почему я сказал своего рода:)

Переопределение сеансов с использованием:

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", без переопределения:

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, чтобы он отправлял [: кроме] члена опций вышеупомянутому (вcode) private методы. Затем вы должны изменить их для добавления маршрутов в зависимости от условий.

Самый быстрый и грязный способ - добавить @scope [: исключением] = опции [: кроме] и затем изменить частныйметоды, так что кроме хэша (если вы решите иметь детальное управление маршрутом, например: :except => {:sessions => [:destroy]}, что делает :skip устаревшим) или массив (если вы хотите удалить это конкретное действие из всех маршрутов, например: :except => [:destroy]), этопроверяйте перед добавлением маршрута.

В любом случае, есть много способов добиться того, что вам нужно.Вам решать, какой из них вы считаете наиболее подходящим.

6 голосов
/ 12 августа 2011

На самом деле devise_for поддерживает :skip и :only, например ( документы ):

devise_for :user, :skip => :registration

Это пропустит все маршруты контроллера регистрации, а не одинв частности.Затем вы можете реализовать маршруты, которые вам нужны.Это кажется более чистым, чем удаление маршрута после факта.

ОБНОВЛЕНИЕ:

Другое возможное решение состоит в том, чтобы использовать в Rails функцию advanced links для блокировкиполностью нежелательный маршрут:

# config/routes.rb
constraints lambda {|req| req.url =~ /users/ && req.delete? ? false : true} do
  devise_for :users
end

Вот сообщение об использовании лямбда-выражений для ограничений маршрута .Объект запроса объяснен здесь .Это может быть самое простое решение.

2 голосов
/ 28 сентября 2016

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

...