noplans_rubyの日記 RSSフィード

 | 

2008-01-03

[]restful_authentication を題材にして routes, resource and resources のお勉強

(追記: この記事よりも、 ActiveResourceとかそのルーティングとかのドキュメント - moroの日記 を読んだ方が良いと思います!)

(追記その2: restful_authentication の controller_name がバグってたのが直ったようですね。デフォルトも sessions になってます。ですので、以下の記事の session_controller まわりの記事は現在では不必要になってます)

大幅に書き換えました。hatena.vim rocks.

インストール

% cd your_rails_project
% ./script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/

controller の作成

% ./script/generate authenticated model_name [controller_name]

controller_name は省略可能(デフォルトは session)です。今回は model_name を user、controller_name を session にします。

% ./script/generate authenticated user

これで users_controller と session_controller が作られます。モデルなどもできますが、今回は触れません。

RESTful なコントローラにする

まずは users_controller と session_controller を RESTful なコントローラにします。config/route.rb を編集します。

ActionController::Routing::Routes.draw do |map|
  map.resources :users
  map.resource :session
end

map.resource と map.resources の違いについては、http://api.rubyonrails.org/classes/ActionController/Resources.html を参照すると良いと思います。session_controller には :id が必要ない(ログインとログアウトだけに使う)ので、singleton resource を選択しました。この時点で

% rake routes

を行うと、現時点での routes 設定を見ることができます。

usersGET/users{:controller=>"users", :action=>"index"}
formatted_usersGET/users.:format{:controller=>"users", :action=>"index"}
POST/users{:controller=>"users", :action=>"create"}
POST/users.:format{:controller=>"users", :action=>"create"}
new_userGET/users/new{:controller=>"users", :action=>"new"}
formatted_new_userGET/users/new.:format{:controller=>"users", :action=>"new"}
edit_userGET/users/:id/edit{:controller=>"users", :action=>"edit"}
formatted_edit_userGET/users/:id/edit.:format{:controller=>"users", :action=>"edit"}
userGET/users/:id{:controller=>"users", :action=>"show"}
formatted_userGET/users/:id.:format{:controller=>"users", :action=>"show"}
PUT/users/:id{:controller=>"users", :action=>"update"}
PUT/users/:id.:format{:controller=>"users", :action=>"update"}
DELETE/users/:id{:controller=>"users", :action=>"destroy"}
DELETE/users/:id.:format{:controller=>"users", :action=>"destroy"}
POST/session{:controller=>"sessions", :action=>"create"}
POST/session.:format{:controller=>"sessions", :action=>"create"}
new_sessionGET/session/new{:controller=>"sessions", :action=>"new"}
formatted_new_sessionGET/session/new.:format{:controller=>"sessions", :action=>"new"}
edit_sessionGET/session/edit{:controller=>"sessions", :action=>"edit"}
formatted_edit_sessionGET/session/edit.:format{:controller=>"sessions", :action=>"edit"}
sessionGET/session{:controller=>"sessions", :action=>"show"}
formatted_sessionGET/session.:format{:controller=>"sessions", :action=>"show"}
PUT/session{:controller=>"sessions", :action=>"update"}
PUT/session.:format{:controller=>"sessions", :action=>"update"}
DELETE/session{:controller=>"sessions", :action=>"destroy"}
DELETE/session.:format{:controller=>"sessions", :action=>"destroy"}

session_controller の方の :controller 設定が "sessions" になっているのでこれを修正します。"sessions" になっている理由は rails 2.0 で導入された new convention のためだと思います。

We’ve also instigated a new convention that all resource-based controllers will be plural by default

Rails 2.0: It’s done! | Riding Rails

session_controller を見るように変更する

config/routes.rb に書いた先ほどの設定を変更します。

ActionController::Routing::Routes.draw do |map|
  map.resources :users
  map.resource :session, :controller => "session"
end

もう一度 routes 設定を確認します(session部分のみ掲載)。

POST/session{:controller=>"session", :action=>"create"}
POST/session.:format{:controller=>"session", :action=>"create"}
new_sessionGET/session/new{:controller=>"session", :action=>"new"}
formatted_new_sessionGET/session/new.:format{:controller=>"session", :action=>"new"}
edit_sessionGET/session/edit{:controller=>"session", :action=>"edit"}
formatted_edit_sessionGET/session/edit.:format{:controller=>"session", :action=>"edit"}
sessionGET/session{:controller=>"session", :action=>"show"}
formatted_sessionGET/session.:format{:controller=>"session", :action=>"show"}
PUT/session{:controller=>"session", :action=>"update"}
PUT/session.:format{:controller=>"session", :action=>"update"}
DELETE/session{:controller=>"session", :action=>"destroy"}
DELETE/session.:format{:controller=>"session", :action=>"destroy"}

これで、:controller が "session" を見るようになりました。

ログイン、ログアウト、サインアップ用の url を用意する

動作としてはこれで良いのですが、

http://example.jp/login でログイン
http://example.jp/logout でログアウト
http://example.jp/signup でサインアップ

にしたいと思いましたので、config/routes.rb をもう少し変更します。

Routing の基本は http://api.rubyonrails.org/classes/ActionController/Routing.html で知ることができるので、それを見るとだいたいわかると思います。

ActionController::Routing::Routes.draw do |map|
  map.connect "login", :controller => "session", :action => "new"
  map.connect "logout", :controller => "session", :action => "destroy"
  map.connect "signup", :controller => "users", :action => "new"
  map.resources :users
  map.resource :session, :controller => "session"
end

ビューで楽をするために Named routes を利用する

あとは、ビューで link_to などで /login などに飛びたいときにいちいち :controller などを書くのがめんどいので、login_path とか logout_path とかで表現できるようにすると楽です。そのために、map.connect ではなく、map._name_of_root_ を使います。

ActionController::Routing::Routes.draw do |map|
  map.login "login", :controller => "session", :action => "new"
  map.logout "logout", :controller => "session", :action => "destroy"
  map.signup "signup", :controller => "users", :action => "new"
  map.resources :users
  map.resource :session, :controller => "session"
end

たとえば先頭の

  map.login "login", :controller => "session", :action => "new"

を例にとると、こう設定することで、login_url, login_path を利用できるようになります。詳しくは http://api.rubyonrails.org/classes/ActionController/Routing.html の Named routes の項を読むと良いと思います。

Don't Repeat Yourself

:controller => "session" と何度も書くのが嫌なので、まとめてしまいます。with_options を利用します。

ActionController::Routing::Routes.draw do |map|
  map.with_options :controller => "session" do |page|
    page.login "login", :action => "new"
    page.logout "logout", :action => "destroy"
    page.resource :session
  end
  map.signup "signup", :controller => "users", :action => "new"
  map.resources :users
end

session_controller と users_controller の routes 設定の順番が変わってしまいましたが、rake routes で確認したところかぶってるところもないので問題なさそうです。一応結果を表示しておきます。

login /login{:controller=>"session", :action=>"new"}
logout /logout{:controller=>"session", :action=>"destroy"}
POST/session{:controller=>"session", :action=>"create"}
POST/session.:format{:controller=>"session", :action=>"create"}
new_sessionGET/session/new{:controller=>"session", :action=>"new"}
formatted_new_sessionGET/session/new.:format{:controller=>"session", :action=>"new"}
edit_sessionGET/session/edit{:controller=>"session", :action=>"edit"}
formatted_edit_sessionGET/session/edit.:format{:controller=>"session", :action=>"edit"}
sessionGET/session{:controller=>"session", :action=>"show"}
formatted_sessionGET/session.:format{:controller=>"session", :action=>"show"}
PUT/session{:controller=>"session", :action=>"update"}
PUT/session.:format{:controller=>"session", :action=>"update"}
DELETE/session{:controller=>"session", :action=>"destroy"}
DELETE/session.:format{:controller=>"session", :action=>"destroy"}
signup /signup{:controller=>"users", :action=>"new"}
usersGET/users{:controller=>"users", :action=>"index"}
formatted_usersGET/users.:format{:controller=>"users", :action=>"index"}
POST/users{:controller=>"users", :action=>"create"}
POST/users.:format{:controller=>"users", :action=>"create"}
new_userGET/users/new{:controller=>"users", :action=>"new"}
formatted_new_userGET/users/new.:format{:controller=>"users", :action=>"new"}
edit_userGET/users/:id/edit{:controller=>"users", :action=>"edit"}
formatted_edit_userGET/users/:id/edit.:format{:controller=>"users", :action=>"edit"}
userGET/users/:id{:controller=>"users", :action=>"show"}
formatted_userGET/users/:id.:format{:controller=>"users", :action=>"show"}
PUT/users/:id{:controller=>"users", :action=>"update"}
PUT/users/:id.:format{:controller=>"users", :action=>"update"}
DELETE/users/:id{:controller=>"users", :action=>"destroy"}
DELETE/users/:id.:format{:controller=>"users", :action=>"destroy"}
 |