Пространство имен Rails против вложенного ресурса - PullRequest
15 голосов
/ 01 марта 2011

Допустим, у моего приложения есть две модели: Foo и Bar.

Foo опционально принадлежит Bar.

Прямо сейчас я могу посмотреть на один Foo или найти определенный Foo, и FoosController обрабатывает все это. Мои URL-адреса похожи на: foos/1 и foos/new

Иногда я хочу посмотреть на бар. BarsController обрабатывает это, и я получаю это как: bars/1 или bars/1/edit.

Если я смотрю на Бар, возможно, мне захочется просмотреть все ФУ, которые являются частью этого Бар. Итак, я хотел бы использовать bars/1/foos/, чтобы посмотреть на эти Foos.

Это довольно просто для вложенных ресурсов и выглядит так:

resources :foo
resources :bar do
  resources :foo
end

Однако, Foos, которые являются частью бара, являются своего рода особыми, отличными от обычных Foos. Так, например, если я загружу foos/1 или bars/1/foos/1, я бы посмотрел на тот же Foo, но в каждом случае я сосредоточен на различной информации.

Так что я думал о контроллере BarFoos для обработки Foos, когда они находятся в контексте Bar. Однако, если я вложу BarFoos под Bar, то мои помощники будут похожи на bar_bar_foos_path и new_bar_bar_foo_path. Это кажется излишним.

Итак, теперь я думаю о пространствах имен, которые я никогда раньше не изучал. Я вижу в руководстве по рельсам, что я могу определить:

namespace "bar" do
  resources :foos
end

Если я сделаю это, я могу сделать секунду FoosController под app/bar/, и этот FoosController сможет обрабатывать Foos внутри бара с хорошими помощниками, такими как bar_foo_path(:id) вместо bar_bar_foo_path(:id).

Но если я сделаю это, что случится с моим BarsController? Как запросы перенаправляются на BarsController, если вместо resources :bars у меня есть namespace "bar"?

И, наконец, есть ли что-то особенное, что мне нужно сделать внутри моего вторичного FoosController, чтобы убедиться, что нет конфликта имен с FoosController верхнего уровня? Я понимаю, что в маршрутизации указано «пространство имен», но как остальная часть кода ruby ​​узнает, что app/bar/foos_controller и app/foos_controller не принадлежат к одному и тому же классу?

Спасибо!

Ответы [ 2 ]

38 голосов
/ 02 марта 2011

Я думаю, что вы пытаетесь достичь:

  1. Бар имеет много Foos
  2. Просмотр Foos, принадлежащих Бар
  3. Просмотреть все Foos независимо от родителя.

Вы можете достичь этого с помощью: routes.rb:

resources :foos
resources :bars do
  resources :foos, :controller => 'bars/foos'
end

Помощники по маршруту, которые вы получите в итоге:

  • bars_path
  • foos_path
  • bars_foos_path
  • и т.д. =)

По сути, вы получите:

  • app / BarsController (rails g controller controller)
  • app / FoosController (rails g controller foos)
  • app / bars / FoosController (rails g controller bars / foos)

В FoosController вы можете получить доступ к foos как обычно с помощью:

@foos = Foos.all

и в барах / FoosController вы можете получить доступ к foos бара с помощью:

@foos = @bar.foos

где bar может быть предварительно извлечена в контроллере bars / foos с помощью:

before_filter :get_client

private
def get_client
  @bar = Bar.find(params[:bar_id])
end

Надеюсь, это поможет. =) * * Тысячу сорок-пять

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

routes.rb:

namespace :admin do
  resources :foos
end

и я создаю свой контроллер с помощью:

rails g controller admin/foos

Это настраивает мой ресурс foos, так что я могу получить к нему доступ через "URL моего сайта" / admin / foos, а также получить помощников, таких как admin_foos_path.

5 голосов
/ 11 июля 2012

У этого подхода есть минусы.

Если вы объявите константу, например. CONST_NAME, во вложенном ресурсе foos, rails создает исключение "неинициализированная константа :: Foo :: CONST_NAME" из-за алгоритма области действия.

Чтобы избежать такого поведения, используйте:

resources :foos
resources :bars do
  scope :module => "bar" do
    resources :foos #, :controller => 'bar/foos' no need to use this now because route will be searched there by default
  end
end

Теперь вы не получите исключение при использовании:

Foo::CONST_NAME

или

Bar::Foo::CONST_NAME
...