Rails 2.3.8では、ユーザー認証にrestful_authenticationを使っていたのだけど、Rails 3.0ではdeviseが人気のようなので、こちらに移行してみる。
追記
"devise with all the bells and whistles" を作ってみるとして、リベンジ:Rails 2.3RC1で”Restful Authentication with all the bells and whistles”をやってみるで行ったことをdeviseで行ってみた。この二つのエントリーを読み比べてもらえるとわかりやすいと思う。
環境
- Debian GNU/Linux squeeze
- Ruby 1.8.7
- Rails 3.0
- gem 1.3.7
- devise 1.1.2
目標
リベンジ:Rails 2.3RC1で”Restful Authentication with all the bells and whistles”をやってみるでできたことがdeviseを使ってもできるようにする。
- アクティベーションを用いたアカウント作成
- http://localhost:3000/myprojects/users/new でアカウント作成
- 確認メール送信
- メールに記載されたメールアドレスをクリックするとアクティベーション完了
- http://localhost:3000/myprojects/session/new でログイン
- パスワード忘れへの対応(パスワード再発行)
参考
Rails 2.3.8で作成したプロジェクトの3.0への移行
Web+DB press Vol. 58の特集、詳解Rails 3の「第6章 移行の手引き」にしたがって行った。概要だけ述べると以下のとおり。
- Rails 3.0 で新たにプロジェクトを作成する(仮に app_3 とする)
- Rails 2.3.8での既存プロジェクト(仮に app_2とする)の必要なファイルをコピーする。
- app_2/app, db, lib, public, script の必要なファイルをコピーする。
- app_2/config/environments.rb の主要な内容(Rails::Initializer.run do |config| から end の内側で定義されているもの)を app_3/config/application.rb へ移す。
- app_2内でrequireおよび使用しているgemライブラリを、すべて app_3/Gemfile で列挙する。
- Rails 3.0からconfig/routes.rbの書き方が変更になったので、app_2/config/routes.rb の内容を app_3/config/routes.rb へ新記法で書き直す。
- rails server で実行して、あとはエラーメッセージにしたがい動くまで直しつづける
deviseの導入
gemで導入する。
% gem1.8 install devise
app_3/Gemfileに以下を書き加える。
gem 'devise', '1.1.2
deviseを組み込む。app_3/ において以下のコマンドを実行する。
% rails generate devise:install
app_3/views/layouts/application.html.erbに以下を追加。
<p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p>
app_3/config/environments/development.rbに以下を追加。
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
以上で準備終了。
restful_authentication 由来のものを確認
ほとんど、リベンジ:Rails 2.3RC1で”Restful Authentication with all the bells and whistles”をやってみるのとおりに作ってあるので、ここで指定したものを確認する。
- モデル
- permission.rb, role.rb, user.rb, user_mailer.rb, user_mailer.rb
- コントローラー&ビュー
- accounts_controller.rb, passwords_controller.rb, sessions_controller.rb, users_controller.rb
- フィルター(lib/authenticated_system.rbに記載)
- current_user, login_required, not_logged_in_required
私は、各コントローラーでbefore_filterとして、login_requiredとnot_logged_in_requiredを主に使っていた。また、各アクション内でcurrent_userを常用していた。
restful_authentication から deviseへ移行
わたしは、restful_authentication で Userというモデルを作っていた。あとから必要になるかもしれないので、既存のuserモデル関連のものを別名で保存しておく。
% cd app_3/app/models % mv user.rb user.rb.pre % cd ../../db/migrate % mv *_create_users.rb create_users.rb.pre
app_2/config/environment.rbの中身をそのままapp_3/config/application.rbにコピーしている場合、以下の行が含まれていると、deviseでモデルが生成できないので、削除する。
config.active_record.observers = :user_observer
次にモデルを作成する。とりあえず、userというモデルを作成する。
% rails g devise user invoke active_record create app/models/user.rb invoke test_unit create test/unit/user_test.rb create test/fixtures/users.yml create db/migrate/20100905080023_devise_create_users.rb inject app/models/user.rb route devise_for :users
deviseは、モジュールを選択することで様々な機能を追加することができる。GitHub:deviseとLazyLoadLife:Railsの第4世代認証エンジンDeviseのREADMEを翻訳してみたによると。自アプリケーションでパスワード管理をするのに関連するモジュールは以下のとおり(Token Authenticatable、Oauthable省略)
- 自アプリケーションでパスワード管理をするならば必ず選ぶ:Database Authenticatable
- ユーザーが自分でアカウント作成&編集&削除できるようにするならば選ぶ:Registerable
- restful_authenticationで言うactivationが必要ならば選ぶ:Confirmable
- パスワード忘れ対策が必要ならば選ぶ:Recoverable
- 「次回以降自動的にログインする」の機能を実現するならば選ぶ:Rememberable
- ログイン履歴をとるならば選ぶ:Trackable
- 一定期間操作を行っていなければ自動ログアウトを実現するならば選ぶ:Timeoutable
- 入力されたメールアドレスやパスワードのチェックをするならば選ぶ:Validatable
- 規定回数以上ログインに失敗したらアカウントをロックするならば選ぶ:Lockable
私がrestful_authenticationで使っていたのは、1, 2, 3, 4, 5, 8(ただし自作)のモジュール。なので、restful_authenticationで行えたことはdeviseを使って全部実現できる。公開は上の9つのモジュールすべてを使用することにする。
apt_3/db/migrate/*_devise_create_users.rb を以下のようにする(使いたいモジュールに対応する部分をコメントインする)。
class DeviseCreateUsers < ActiveRecord::Migration def self.up create_table(:users) do |t| t.database_authenticatable :null => false t.recoverable t.rememberable t.trackable t.confirmable t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both # t.token_authenticatable t.timestamps end add_index :users, :email, :unique => true add_index :users, :reset_password_token, :unique => true add_index :users, :confirmation_token, :unique => true add_index :users, :unlock_token, :unique => true end def self.down drop_table :users end end
deviseが生成するUsersテーブルの中身の具体的な内容は db/schema.rb を見れば確認できる。
また、app_3/app/models/user.rb を以下のようにする(使用したいモジュールを列挙する)。
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :confirmable, :lockable and :timeoutable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation, :remember_me end
app_3/config/routes.rb 内の restful_authentication に関わる設定をすべてコメントアウトするか消す。私の場合は以下のものが該当する。
match 'signup' => 'users#new', :as => 'signup' match 'login' => 'sessions#new', :as => 'login' match 'logout' => 'sessions#destroy', :as => 'logout' match 'forgot_password' => 'passwords#new', :as => 'forgot_password' match 'change_password' => 'accounts#edit', :as => 'change_password' match 'activate/:id' => 'accounts#show' match 'reset_password/:id' => 'passwords#edit'
また、以下を追加してログイン後のリダイレクト先を指定する。私の場合はユーザーのトップ画面をusers#showにしていたので、それを踏襲する。
# root root :to => 'users#show' # for devise devise_for :users get 'users', :to => 'users#show', :as => :user_root
devise関連のビューを編集できるようにするためにビューをローカルに生成する。
% rails generate devise:views
app_3/app/view/devise 以下に生成されるディレクトリと同名のコントローラーがあると不備が生じるのでとりあえず別名にしておくこと。具体的には以下のコントローラー。括弧内はたぶん対応すると思われるモジュール名。
- confirmations_controller(対応:Confirmable)
- passwords_controller(対応:Recoverable)
- registrations_controller(対応:Registerable)
- sessions_controller(対応:Database Authenticatable)
- unlocks_controller(対応:Lockable)
app_3/app/controllers/users_controller.rbから、restful_authentication由来のフィルタを外し、deviseのフィルターを入れる。外すフィルターは以下のとおり。
before_filter :not_logged_in_required, :only => [:new, :create] before_filter :login_required, :only => [:show, :edit, :update]
login_requiredを以下に置き換える。
before_filter :authenticate_user!, :only => [:show, :edit, :update]
データベースを更新して、サーバーを動かせばちゃんと動くはず。うごかない場合にはrestful_authentication由来の関数が存在するのが原因。
% rake db:migrate % rails server
メソッドの対応は多分こんな感じ
restful_authentication | devise | ||
current_user | current_user | ||
before_filter :login_required | before_filter :authenticate_user! | ||
logged_in? | user_signed_in? |
とりあえず、ここまで。