restful_authenticationを使ってみた

Tsukasa OISHI

Railsでユーザ認証といえばacts_as_authenticatedだと思っていたのですが、今はもうrestful_authenticationというやつが出てきているようです。けっこう前から? アンテナ低いのはなんとかしなければ。とりあえず、今開発中のかえるキーワードで使ってみることにした。
まずはインストール。

./script/plugin source http://svn.techno-weenie.net/projects/plugins
./script/plugin install restful_authentication

restful_authenticationは、acts_as_state_machineというやつを使うのでこいつもインストール。

./script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk/

それからacts_as_authenticatedみたいにモデルやらコントローラを作ります。

./script/generate authenticated user sessions \
              --include-activation \
              --stateful

これでuser, user_mailer, user_observerモデルと、user, sessionコントローラが作られます。
モデルのほうはacts_as_authenticatedでおなじみのやつらと一緒。オブサーバを使うので、config/environment.rbのInitializerブロックの中で

config.active_record.observers = :user_observer

と指定しておきます。
acts_as_authenticatedではaccountコントローラひとつだったけど、アカウント管理関係はuserコントローラに、ログイン処理関係はsessionコントローラにわかれています。
上記で--include-activationと定義しているけど、これだけでメールを使ったユーザ登録処理が実装される。これは便利ですね。acts_as_authenticatedでは自分で書いていたから。
--statefulはacts_as_state_machineを使ってユーザの管理をするよ、という宣言。acts_as_state_machineなんてはじめてきいたけど、userモデルを読むとなんとなくわかる。

  acts_as_state_machine :initial => :pending
  state :passive
  state :pending, :enter => :make_activation_code
  state :active,  :enter => :do_activate
  state :suspended
  state :deleted, :enter => :do_delete

こんな感じで状態が宣言されている。initialが初期状態で、enterキーでその状態になったときに実行するメソッドを示しているみたいだ。
さらに、

  event :register do
    transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
  end

こんな感じで状態が変化するイベントを定義する。イベントは

current_user.activate!

といったようにUserインスタンスのメソッドとして「!」つきでコールすればいいみたい。なかなかおもしろい。
で、あとは rake db:migrate を実行すればOK。ログイン時にメールアドレスを使用したかったらちょっと書き直さなければいけないのはacts_as_authenticatedと同様。あと、reset_sessionを要所要所に追加したほうがよさそうです。
本登録の認証のため、avtivateはactivate_codeパラメータを受け取れるようにmap.connectで別に書くか、デフォルトのルーティングを生かして、activateコードをidで受け取るように書き換える必要があります。
これでとりあえず動きますが、ユーザの状態管理をするならconfig/routesの設定もしておきます。

  map.resources :users, :member => {:suspend => :put, :unsuspend => :put, :purge => :delete}
  map.resource :session

ユーザ状態の変更アクションはusers_pathへリダイレクトするので、indexアクションを用意しておきましょう。