#どんな記事?
ここではrailsでアプリを作る際に認証機能を簡単に作成するgemである'devise'を使う時の、コントローラーとビュー、URLをカスタマイズする方法とその考え方を解説する。
#deviseとは
$ rails g devise モデル名
とするだけでモデルを作成してくれて、内部的にビューやコントローラーも作成される。
そのためこのコマンドをうつだけで、モデル、ビュー、コントローラーの三つを作成することができる。
非常に簡単にログイン認証の仕組みを作ることができる。
逆に言うと
デフォルトで設定される URL
デフォルトで使用されるコントローラー
デフォルト使用されるビュー
が存在するため、 細かい設定をするためには色々と変更しなければならない。 今回はその設定方法と考え方について解説する。
#デフォルトではどうなっているか
まず、
$ rails g devise member
とするとmemberモデルが作成され ルーティングは以下のようになる(必要部分だけ)。
Prefix Verb URI Pattern Controller#Action
new_member_session GET /members/sign_in(.:format) devise/sessions#new
member_session POST /members/sign_in(.:format) devise/sessions#create
destroy_member_session DELETE /members/sign_out(.:format) devise/sessions#destroy
new_member_password GET /members/password/new(.:format) devise/passwords#new
edit_member_password GET /members/password/edit(.:format) devise/passwords#edit
member_password PATCH /members/password(.:format) devise/passwords#update
PUT /members/password(.:format) devise/passwords#update
POST /members/password(.:format) devise/passwords#create
cancel_member_registration GET /members/cancel(.:format) devise/registrations#cancel
new_member_registration GET /members/sign_up(.:format) devise/registrations#new
edit_member_registration GET /members/edit(.:format) devise/registrations#edit
member_registration PATCH /members(.:format) devise/registrations#update
PUT /members(.:format) devise/registrations#update
DELETE /members(.:format) devise/registrations#destroy
POST /members(.:format) devise/registrations#create
ここで抑えて欲しいのは
・URL(の先頭)には members(モデル名+s)がつく
・コントローラーは devise/〇〇 が使われるということ。(railsアプリのディレクトリ内にあるわけではない)
では、デフォルトの状態からどんなカスタマイズをしたくなるか、以下のようなパターンがある。
- ビューをカスタマイズしたい(デフォルトはダサいので誰もがしたくなるはず)
- URLをカスタマイズしたい(ユーザーから見える部分だから綺麗にしたくなったりする)
- モデルごとに使用するコントローラを変更したい(コントローラーの挙動をカスタマイズしたい)
#コントローラーのカスタマイズ
デフォルトではdevise/〇〇が使われていたがこれを直接編集することはできない。
なので、コマンドでコントローラーを作成し、そのコントローラーを操作したいモデルに割り当て、それを編集する。
挙動のカスタマイズは人ぞれぞれなので、割り当てについて説明する。
$ rails g devise:controllers members
とするとapp/controllers/membersの中にコントローラが作られる
しかしまだ、コントローラーを作っただけなのでルーティングは上のものと変化していない。
つまりまだmemberモデルはdevise/〇〇のコントローラ を使ってしまう。なので、memberモデルに今作ったcontrollers/members内のコントローラを割り当てる作業をする。
Rails.application.routes.draw do
devise_for :members
end
を次のように変更する
Rails.application.routes.draw do
#devise_for :members
#使用するコントローラをapp/contorolers/members内のものにできる
devise_for :members, module: "members"
end
もしくは次のようにしても良い
Rails.application.routes.draw do
#devise_for :members
#以下ようにしても同様に、使用するコントローラをapp/contorolers/members以下にできる
#コントローラーの指定をより細かくできるという違いがある
devise_for :members, :controllers => {
:sessions => 'members/sessions',
:passwords => 'members/passwords',
:registrations => 'members/registrations'
}
end
こうするとルーティングは次のようになり、memberモデルに今作ったcontrollers/members内のコントローラが割り当てられる。ここまできてようやくコントローラーがカスタマイズできる。
##ちなみに
今回はmemberモデルに対応するコントローラ ということでrails g devise:controllers maembers
としたがrails g devise:controllers aaa
でも大丈夫だ。(単数形でも大丈夫、モデル名と一致させなくてもroutes.rbで割り当てをするので大丈夫)
その場合以下のようにする
#これか
devise_for :members, module: "aaa"
#もしくはこれ
devise_for :members, :controllers => {
:sessions => 'aaa/sessions',
:passwords => 'aaa/passwords',
:registrations => 'aaa/registrations'
}
#ビューのカスタマイズ
まず、前提として、基本的にビューはコントローラのアクションが実行されてから呼び出される。つまり、ビューはコントローラーと連携してる必要がある
これをしっかり覚えておいてください。
では、ビューをカスタマイズ
以下のコマンドでビューファイルを作成
$ rails g devise:views XXXs
app/views/XXXsディレクトリが作成され、その中にビューファイルが作られる。
XXXsはディレクトリ名になるわけだが、このディレクトリ名が重要。
rails g devise:controllers maembers
で作った、controllers/members内のコントローラで呼び出されるビューをカスタマイズするのであれば$ rails g devise:views members
とする。
つまり、コントローラーのディレクトリ名とビューのディレクトリ名は一致していないといけない。
また、XXXを省略して$ rails g devise:views
とするとディレクトリ名はdeviseになる(デフォルトのdevise/〇〇のコントローラで呼び出されるビューをカスタマイズできる)
ここの話は、deviseで作られたモデルが複数ある時のがわかりやすいので、memberモデルとuserモデルを作ったとして改めて説明する。
(一から作ってビューやコントローラーは何もカスタマイズしていないものを考える。)
$ rails g devise member
$ rails g devise user
この時ルーティングは次のようになる。
ここからわかるように、
現状、userモデルもmemberモデルも devise/〇〇のコントローラーを使ってしまうので、memberモデルには新たに、members内にコントローラを作ってそれを割り当てる作業をする。(先ほど説明した通り)
rails g devise:controllers maembers
してからroutes.rbを編集(上で説明した通り)
Rails.application.routes.draw do
#devise_for :members
devise_for :members, module: "members"
devise_for :users
end
そうするとルーティングは以下のようになる。
これで、各モデルごとに異なるコントローラーを割り当てることができた。
では、ここでuserモデルを操作するためのビューをカスタマイズするにはどうするのか
そう、$ rails g devise:views
とすればよかった。なぜなら、「userモデルの操作を担当するコントローラーは__devise__/〇〇だから、viewフォルダ内では__devise__ディレクトリ内にビューファイルを作ればいい」からだ。
では、membersモデルを操作するためのビューをカスタマイズするにはどうするのか
そう、$ rails g devise:views members
とすればよかった。なぜなら、「memberモデルの操作を担当するコントローラーは__members__/〇〇だから、viewフォルダ内では__members__ディレクトリ内にビューファイルを作ればいい」からだ。
もちろん
rails g devise:controllers maembers
rails g devise:controllers users
としてから
Rails.application.routes.draw do
#devise_for :members
#devise_for :users
devise_for :members, module: "members"
devise_for :users, module: "users"
end
としても良い
(というかするのが一般的ではある...気がする... どっちか一方のコントローラーだけdeviseのままなのは変な感じがする)
くどくなってきたが、大事なのは
コントローラーのディレクトリ名に合わせてビューを作ろう
ということだ。
##注意
deviseでコントローラーをカスタマイズするときも、基本的にコントローラー名は複数形にすべきだが、単数でも大丈夫と説明した。
rails g devise:controllers member
でもちゃんとディレクトリは作られる。
この時ビューをカスタマイズするのであれば、ビューファイルは app/views/member内にないといけない。
ならば
rails g devise:views member
とするべきだろう。
しかし、このビューを作るコマンドでは、作られるディレクトリは必ず複数形になって作られてしまう。
つまり、
rails g devise:views member
としてもapp/views/member内にビューファイルはできずにapp/views/members内にできる。
なので、コントローラ 名を単数形にしたい時、かつ、ビューファイルをカスタマイズしたいときは、一旦ディレクトリ名を複数形でビューファイルを作成してから、手動でディレクトリ名を変更する必要がある。
#URLのカスタマイズ
一番最初に、URL(の先頭)には members(モデル名+s)がつくと説明した。こういうのを変えたかったり、sign_inをloginに変えたかったりすることがある。
###デフォルトのURLの先頭を変える方法
memberモデルがあるときデフォルトは /members/sign_in
とか /members/sign_up
とかになっている。
これを/aaaa/sign_in
とか /aaaa/sign_up
にするなら以下。
Rails.application.routes.draw do
#devise_for :members
devise_for :members, path: 'aaaa'
end
先頭の/members
を無くして/sign_in
とか /sign_up
にするなら以下。
Rails.application.routes.draw do
#devise_for :members
devise_for :members, path: ''
end
###/sign_inをloginにしたりする方法
Rails.application.routes.draw do
#devise_for :members
devise_for :members, path_names: {
sign_in: 'login', sign_out: 'logout',
password: 'secret', confirmation: 'verification',
registration: 'register', edit: 'edit/profile'
}
end
#まとめ
これまでの説明を踏まえると、例えば以下のようになる
$ rails g devise member
$ rails g devise user
$ rails g devise:controllers members
$ rails g devise:views members
$ rails g devise:controllers admins
$ rails g devise:views admins
Rails.application.routes.draw do
devise_for :members,
module: "members",
path: '',
path_names: {
sign_in: 'login', sign_out: 'logout',
password: 'secret', confirmation: 'verification',
registration: 'register', edit: 'edit/profile'
}
devise_for :users,
module: "admins",
path: "admin"
end
[vagrant@localhost devise-app]$ rails routes
Prefix Verb URI Pattern Controller#Action
new_member_session GET /login(.:format) members/sessions#new
member_session POST /login(.:format) members/sessions#create
destroy_member_session DELETE /logout(.:format) members/sessions#destroy
new_member_password GET /secret/new(.:format) members/passwords#new
edit_member_password GET /secret/edit(.:format) members/passwords#edit
member_password PATCH /secret(.:format) members/passwords#update
PUT /secret(.:format) members/passwords#update
POST /secret(.:format) members/passwords#create
cancel_member_registration GET /register/cancel(.:format) members/registrations#cancel
new_member_registration GET /register/sign_up(.:format) members/registrations#new
edit_member_registration GET /register/edit/profile(.:format) members/registrations#edit
member_registration PATCH /register(.:format) members/registrations#update
PUT /register(.:format) members/registrations#update
DELETE /register(.:format) members/registrations#destroy
POST /register(.:format) members/registrations#create
new_user_session GET /admin/sign_in(.:format) admins/sessions#new
user_session POST /admin/sign_in(.:format) admins/sessions#create
destroy_user_session DELETE /admin/sign_out(.:format) admins/sessions#destroy
new_user_password GET /admin/password/new(.:format) admins/passwords#new
edit_user_password GET /admin/password/edit(.:format) admins/passwords#edit
user_password PATCH /admin/password(.:format) admins/passwords#update
PUT /admin/password(.:format) admins/passwords#update
POST /admin/password(.:format) admins/passwords#create
cancel_user_registration GET /admin/cancel(.:format) admins/registrations#cancel
new_user_registration GET /admin/sign_up(.:format) admins/registrations#new
edit_user_registration GET /admin/edit(.:format) admins/registrations#edit
user_registration PATCH /admin(.:format) admins/registrations#update
PUT /admin(.:format) admins/registrations#update
DELETE /admin(.:format) admins/registrations#destroy
POST /admin(.:format) admins/registrations#create
#参考
https://qiita.com/akasakas/items/138c29fa2cecd271cfe4
https://qiita.com/ryosuketter/items/9240d8c2561b5989f049
https://www.rubydoc.info/github/heartcombo/devise/master/ActionDispatch/Routing/Mapper
特に3つ目のやつ見てください。