Rails 5 — вложенные маршруты — неинициализированные константы для контроллеров

Я пытаюсь понять, как вкладывать маршруты в Rails 5 (чтобы связанные контроллеры хранились вместе.

У меня есть файловое дерево контроллеров, настроенное как:

 app/controllers/users

В этой папке у меня есть контроллеры для:

identities_controller.rb
app_roles_controller.rb

Каждый из этих контроллеров сохраняется как:

class Users::IdentitiesController < ApplicationController
class Users::AppRolesController < ApplicationController

В моем файле маршрутов есть:

resources :app_roles,
    :controllers => {
      :app_roles => 'users/app_roles'
    }

  devise_for :users,
             :controllers => {
                :sessions => 'users/sessions',
                :registrations => "users/registrations",
                :omniauth_callbacks => 'users/omniauth_callbacks'
              }

  resources :identities, 
    :controllers => {
        :identities => 'users/identities'
    }

  resources :users

В моей папке представлений все файлы находятся на верхнем уровне. Мне неясно, нужно ли мне группировать их так же, как я делаю свои контроллеры.

Когда я сохраняю все это и пытаюсь перейти к http://localhost:3000/app_roles#index, Я ожидаю перейти к моему приложению/views/app_roles/index.

Вместо этого я получаю сообщение об ошибке:

app_roles
uninitialized constant AppRolesController

Когда я разгребаю маршруты, я получаю:

rake routes | grep app_roles
                       app_roles GET      /app_roles(.:format)                    app_roles#index {:controllers=>{:app_roles=>"users/app_roles"}}
                                 POST     /app_roles(.:format)                    app_roles#create {:controllers=>{:app_roles=>"users/app_roles"}}
                    new_app_role GET      /app_roles/new(.:format)                app_roles#new {:controllers=>{:app_roles=>"users/app_roles"}}
                   edit_app_role GET      /app_roles/:id/edit(.:format)           app_roles#edit {:controllers=>{:app_roles=>"users/app_roles"}}
                        app_role GET      /app_roles/:id(.:format)                app_roles#show {:controllers=>{:app_roles=>"users/app_roles"}}
                                 PATCH    /app_roles/:id(.:format)                app_roles#update {:controllers=>{:app_roles=>"users/app_roles"}}
                                 PUT      /app_roles/:id(.:format)                app_roles#update {:controllers=>{:app_roles=>"users/app_roles"}}
                                 DELETE   /app_roles/:id(.:format)                app_roles#destroy {:controllers=>{:app_roles=>"users/app_roles"}}

Мне кажется, эти маршруты показывают, что app_roles#index должен идти в app/views/app_roles/index.html.erb через контроллер в app/controllers/users/app_roles_controller.rb

У меня такая же проблема с ресурсом удостоверений.

ДОГАДАНИЯ Я попытался переместить папку app/views/app_roles в папку пользователей (т. е. app/views/users), но получаю ту же ошибку, когда затем пытаюсь перейти к папке http://localhost:3000/app_roles#index, чтобы проверить, работает ли он.

Я также попытался изменить файл маршрутов на:

resources :app_roles,
        :resources => {
          :app_roles => 'users/app_roles'
        }

Под этим я подразумеваю, что я изменил ссылку на :controllers на :resources. Не помогло - та же ошибка.

Может ли кто-нибудь увидеть, что я делаю неправильно?


person Mel    schedule 07.10.2016    source источник
comment
возможно, попробуйте поместить свои файлы в папку с пространством имен, например app/controllers/users/<my_controller>.rb.   -  person max pleaner    schedule 08.10.2016
comment
они находятся в: приложение/контроллеры/пользователи   -  person Mel    schedule 08.10.2016
comment
у тебя тоже есть app/controllers/user_controller? Он может содержать только class UsersController < ApplicationController; end   -  person max pleaner    schedule 08.10.2016
comment
Да - мой UsersController находится на верхнем уровне (не вложен в папку app/controllers/users)   -  person Mel    schedule 08.10.2016


Ответы (1)


Маршрутизация к контроллерам пространства имен

Чтобы направить ресурсы на контроллер с «пространством имен», вы можете использовать параметр module:

resources :identities, module: :users

Или scope module:, который полезен при объявлении нескольких ресурсов:

scope module: :users do
  resources :app_roles, module: :users
  resources :identities, module: :users
end

Это намного чище, чем указание контроллера вручную, что на самом деле делается только тогда, когда вы переопределяете библиотеку, такую ​​​​как Devise, или когда имена контроллера и маршрута не совпадают.

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

Поиск просмотров

Мне кажется, эти маршруты показывают, что app_roles#index должен идти в app/views/app_roles/index.html.erb через контроллер в app/controllers/users/app_roles_controller.rb

Ну, это не так. Rails ищет представления на основе вложенности класса контроллера. Таким образом, рельсы будут искать представления для Users::IdentitiesController в views/users/indentities/.

Если вы хотите нарушить соглашения, вы можете явно отображать представления или добавлять/добавлять пути просмотра. Однако изучите соглашения, прежде чем нарушать их, на самом деле они довольно умны.

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

«пространства имен» и вложенные маршруты

Маршруты, которые вы создаете, не являются вложенными. Вложенный маршрут будет, например:

POST /users/:user_id/identities

Который ясно описывает намерение. Чтобы настроить вложенные маршруты для indentities, вы должны сделать:

resources :users, shallow: true do
  scope module: :users do
    resources :identities
  end
end

shallow: true генерирует отдельные маршруты без префикса users/:used_id/.

           Prefix Verb   URI Pattern                              Controller#Action
  user_identities GET    /users/:user_id/identities(.:format)     users/identities#index
                  POST   /users/:user_id/identities(.:format)     users/identities#create
new_user_identity GET    /users/:user_id/identities/new(.:format) users/identities#new
    edit_identity GET    /identities/:id/edit(.:format)           users/identities#edit
         identity GET    /identities/:id(.:format)                users/identities#show
                  PATCH  /identities/:id(.:format)                users/identities#update
                  PUT    /identities/:id(.:format)                users/identities#update
                  DELETE /identities/:id(.:format)                users/identities#destroy
            users GET    /users(.:format)                         users#index
                  POST   /users(.:format)                         users#create
         new_user GET    /users/new(.:format)                     users#new
        edit_user GET    /users/:id/edit(.:format)                users#edit
             user GET    /users/:id(.:format)                     users#show
                  PATCH  /users/:id(.:format)                     users#update
                  PUT    /users/:id(.:format)                     users#update
                  DELETE /users/:id(.:format)                     users#destroy
person max    schedule 09.10.2016
comment
Привет Макс, большое спасибо за объяснение. Когда я делаю неглубокое вложение, означает ли это, что я должен хранить папку с представлениями удостоверений, вложенную в папку с представлениями пользователей? Я хочу сделать это для аккуратности в своей файловой структуре, но я интуитивно не понимаю, что отключает мелкий переключатель в файловой структуре представлений. - person Mel; 09.10.2016
comment
Маршруты не влияют на то, как контроллер ищет представления. Они просто вызывают соответствующий контроллер#action - person max; 09.10.2016
comment
Поиск представления определяется только тем, как объявлен класс контроллера. Если он заключен в модуль, то rails будет использовать этот модуль при поиске. - person max; 09.10.2016
comment
Хорошо, но когда вы говорите «завернутый в модуль», вы имеете в виду, что то, как я написал свои вложенные контроллеры, соответствует формату «завернутого в модуль»? Первая строка моих вложенных контроллеров: class Users::IdentitiesController ‹ ApplicationController - person Mel; 09.10.2016
comment
Большое спасибо за объяснения. Я изо всех сил пытаюсь понять жаргон, и я не могу найти хорошие, простые английские переводы документации ruby. - person Mel; 09.10.2016
comment
Привет Макс, я все еще очень смущен. Я пытаюсь создать папки в папке моей модели, которые вкладывают вложенные контроллеры в папку для контроллера верхнего уровня. Я не могу найти простой учебник на английском языке, чтобы объяснить, что мне нужно сделать, чтобы подключить это так, как хочет рельс. Я был бы очень признателен, если бы вы могли дать мне терминологию, которую я могу использовать для поиска помощи, чтобы выяснить, как настроить модели, чтобы я мог хранить соответствующие модели, сгруппированные по папкам. Я продолжаю находить вещи, говорящие о вложенных атрибутах для форм, но я думаю, что это другое. - person Mel; 15.10.2016
comment
Я думаю, что главное в том, что вы путаете 3 разные вещи, которые имеют одинаковую терминологию, но очень разные. - person max; 15.10.2016
comment
У вас есть вложенность модулей или пространства имен, которые представляют собой конструкцию Ruby. Это то, что вы используете, например, для группировки моделей, таких как Users::Credential, например. Rails автоматически загружает приведенные выше константы, просматривая пути автозагрузки для /users/credential.rb. Поэтому, если у вас есть app/models/users/credential.rb, рельсы автоматически загрузят его для вас. - person max; 15.10.2016
comment
Вы можете использовать имя маршрута. Что в основном добавляет префикс к маршруту. Довольно распространенным примером является использование /admin/posts, например, для создания панели инструментов для приложения блога. Обычно это используется вместе с размещением контроллера в модуле (Admin::PostsController), но это не обязательно. - person max; 15.10.2016
comment
Вы можете вкладывать маршруты и атрибуты. Вложенный маршрут будет /users/1/posts отображать сообщения, принадлежащие пользователю. Вы можете вкладывать атрибуты, чтобы вы могли создавать несколько элементов из одного хэша параметров простым способом. List.create( { name: 'Grocieries', items_attributes: [ { value: 'Milk'},{ value: 'Cookies' } ] } ) - person max; 15.10.2016