概要
かんたんログイン(テストユーザーログイン)実装にあたり、普段しない形でコントローラファイルを作成しました。
その際に「え、これどうなってんの?」と感じたことがあったのでそれを記録します。
環境
-
macOS Catalina 10.15.6
-
ruby 2.6.5
-
Rails 6.0.3.4
-
MySQL : 5.6.47
今回やりたいこと
-
[URL] localhost:3000/admin/usersにアクセス
-
app/controllers/admin/users_controller.rbのindexアクションへルーティング
-
index.html.erbを表示
まず、普通のusersコントローラで動作確認
ターミナルで以下のコマンドを入力します。
% rails _6.0.0_ new controller-app -d mysql
% cd controller-app
% rails db:migrate
% rails g controller users
また、ルーティングは以下の通り設定します。
Rails.application.routes.draw do
resources :users, only: :index
end
HTTP Verb | URI Pattern | Controller#Action |
---|---|---|
GET | /users | users#index |
そしてコントローラにindexアクションを追加します。
class UsersController < ApplicationController
def index
end
end
最後に、ビューを追加します。
<h1>users#index</h1>
これで準備完了。
試しに'/users'にアクセスすると…
普通にビューが表示されました!
では、ここから手を加えていきます!
コントローラをadminディレクトリに移動
1. adminディレクトリに移動すると?
-
app/controllers/adminディレクトリを作成
-
その中にusers_controller.rbを移植
-
'/users' にアクセスしてみる
uninitialized constant UsersController
というルーティングエラーが出ています。
これは「定数やクラスが定義されていないエラー」です。
現状を整理すると、
-
GET '/users' をリクエスト
-
users#index (usersコントローラ) を探す
-
そんなのないよ!というエラー
ん?もう一度usersコントローラを見てみましょう。
class UsersController < ApplicationController
def index
end
end
class UsersControllerって書いてるじゃん!
と言いたいところですが、これはシンプルに記述のミスです。
どういうことかというと…
-
今のルーティングの定義だと app/controllers ディレクトリ直下のコントローラファイルを探す
-
ルーティング参照先を app/controllers/admin ディレクトリ直下に変更する必要がある
さて、これをどう実現するか?
次で説明します。
2. namespaceをルーティングに設定
こちらのRailsガイドの2.6を参照しました。
app/controllers/adminディレクトリのコントローラを参照したい際は、次のようにルーティングを設定します。
Rails.application.routes.draw do
namespace :admin do
resources :users, only: :index
end
end
HTTP Verb | URI Pattern | Controller#Action |
---|---|---|
GET | /admin/users | admin/users#index |
これでadminディレクトリのusersコントローラを参照できるようになりました。
では、実際に'admin/users'にアクセスしましょう!
だめですか…。
とりあえずエラー文を解読しましょう。
expected file /Users/***/app/controllers/admin/users_controller.rb to define constant Admin::UsersController, but didn't
-
定数Admin::UsersControllerを定義するため
-
/Users/***/admin/users_controller.rb というファイルが必要
-
でも定義せんかったわ
現状、admin/users_controller.rb
は指定のパスに入っています。
なのでここで出てきたAdmin::UsersControllerをクラス名に定義すれば良さそうです。
というわけでコントローラを以下のように変更します。
class Admin::UsersController < ApplicationController
def index
end
end
これでどうでしょう?
まだダメでした。もうひと作業必要なようです。
もう少し頑張りましょう!
3. ビューファイルを移動
さて、先程のエラー文を解読します。
-
Admin::UsersController#index is missing a template for request formats
-
Admin::UsersController#indexはリクエストフォーマットに対応するテンプレートがありません
リクエストフォーマットって何?と思いましたが、続く小さい文字にヒントがありました。
-
Unless told otherwise, Rails expects an action to render a template with the same name, contained in a folder named after its controller.
-
特に明記されてなければ、Railsは同じ名前のテンプレートをレンダリングするアクションを想定しています
-
コントローラにちなんで名付けられたフォルダに含まれています
つまり「Admin::UsersControllerがレンダリングするビューがないよ」ということです。
そしてそのファイルはコントローラ名に対応したディレクトリに配置する必要がありそうです。
少し具体的に考えると、
-
UsersControllerのindexアクションは
-
app/views/users/index.html.erbのビューをレンダリングする
よって、今回のケースでは、
-
Admin::UsersControllerのindexアクションなので
-
app/views/admin/users/index.html.erb
にビューファイルをセットすればいいと考えられます。
というわけで変更します!
<h1>admin/users/index.html.erb</h1>
さあ、どうでしょうか。
やりました!これで目的達成です!
まとめ
app/controllersにディレクトリを作ってコントローラファイルを配置するときの注意
-
ルーティングにnamespaceを設定
-
クラス名をAdmin::UsersControllerのように変更 (ディレクトリ名を追加)
-
同名ディレクトリ直下にビューファイルを設置
これで実現できます。
ちなみに、今回のケースではURLが変わってしまいました。
これはnamespaceの代わりにmoduleを設定すればURLはそのままになります。
Rails.application.routes.draw do
scope module: :admin do
resources :users, only: :index
end
end
HTTP Verb | URI Pattern | Controller#Action |
---|---|---|
GET | /users | admin/users#index |
勉強になりました!これからも地道にRailsのことを学習していきます!