Маршрутизация Rails 3 — указание точного контроллера из пространства имен

#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.