#ruby-on-rails #ruby-on-rails-3 #routing
#ruby-on-rails #ruby-on-rails-3 #маршруты
Вопрос:
У меня возникла небольшая проблема с пространствами имен маршрутов, с которой я раньше не сталкивался. На самом деле это часть некоторой разработки gem, которой я занимаюсь, но я переработал проблему, чтобы она соответствовала более общей ситуации rails.
В принципе, у меня есть маршрут с пространством имен, но я хочу, чтобы он направлялся к универсальному контроллеру (верхнего уровня).
Мой контроллер — это PublishController
, который обрабатывает публикацию множества различных типов моделей, которые все соответствуют одному интерфейсу, но могут находиться в разных пространствах имен. Мои маршруты выглядят следующим образом:
# config/routes.rb
namespace :manage do
resources :projects do
get 'publish' => 'publish#create'
get 'unpublish' => 'publish#destroy'
end
end
Проблема в том, что это создает следующие маршруты:
manage_project_publish GET /manage/projects/:project_id/publish(.:format) {:controller=>"manage/publish", :action=>"create"}
manage_project_unpublish GET /manage/projects/:project_id/unpublish(.:format) {:controller=>"manage/publish", :action=>"destroy"}
Какие маршруты я хочу, просто не сопоставляя с правильным контроллером. Я перепробовал все, что мог придумать, чтобы попытаться разрешить контроллеру не переносить пространство имен, но я в тупике.
Я знаю, что мог бы сделать следующее:
get 'manage/features/:feature_id/publish' => "publish#create", :as => "manage_project_publish"
который производит:
manage_project_publish GET /manage/projects/:project_id/publish(.:format) {:controller=>"publish", :action=>"create"}
но в идеале я бы предпочел использовать вложенное объявление (для удобства чтения) — если это вообще возможно; что я начинаю думать, это не так.
Ответ №1:
ресурс принимает необязательный хэш, в котором вы можете указать контроллер, чтобы
resource :projects do
было бы записано как
resource :projects, :controller=>:publish do
Ответ №2:
Используйте scope
вместо namespace
, когда вам нужен маршрут с ограниченной областью, но не контроллер в модуле с тем же именем.
Комментарии:
1. Первоначально я тоже думал сделать это — но, к сожалению, поскольку на самом деле это должно быть упаковано как вспомогательный метод маршрута как часть gem, у меня нет контроля над методом переноса. Следовательно, почему я искал способ «вырваться» из текущего пространства имен.
2. и область видимости не создает именованные маршруты AFAIK
3. Вы можете сделать это с помощью
as: :blah
в конце области видимости.4. Если бы я мог проголосовать за это снова, я бы так и сделал. Это довольно скудное знание в контексте.
Ответ №3:
Если я правильно вас понимаю, вы хотите это:
scope :manage do
resources :projects, :only => [] do
get 'publish' => 'publish#create'
get 'unpublish' => 'publish#destroy'
end
end
чтобы настроить эти маршруты:
project_publish GET /projects/:project_id/publish(.:format) {:action=>"create", :controller=>"publish"}
project_unpublish GET /projects/:project_id/unpublish(.:format) {:action=>"destroy", :controller=>"publish"}
Я правильно понимаю вашу потребность? Если да, то это то, что объясняет Райан.
Комментарии:
1. Вы правы,
scope
идеально подходит для этого случая, когда вы хотите, чтобы URL был ограничен, но контроллера не было в URL.2. Спасибо, Уильям, я мог бы поклясться, что пробовал это в то время, но мне придется откопать проект и взглянуть.
Ответ №4:
Я думаю, что вы хотите это:
namespace :manage, module: nil do
resources :projects do
get 'publish' => 'publish#create'
get 'unpublish' => 'publish#destroy'
end
end
Это создает именованные маршруты по вашему желанию (manage_projects …), но все равно вызывает контроллер ::Publish
Ответ №5:
Немного поздно, но для тех, кто все еще борется с этим, вы можете добавить косую черту к имени контроллера, чтобы удалить его из любого существующего пространства имен.
concern :lockable do
resource :locks, only: [] do
post "lock" => "/locks#create"
post "unlock" => "/locks#destroy"
end
end
Теперь, если вы включите эту проблему в любом месте (с пространством имен или нет), вы всегда будете обращаться к LocksController.