#210 Customizing Devise
- Download:
- source codeProject Files in Zip (164 KB)
- mp4Full Size H.264 Video (13.2 MB)
- m4vSmaller H.264 Video (8.32 MB)
- webmFull Size VP8 Video (23.3 MB)
- ogvFull Size Theora Video (17.4 MB)
前回のエピソード[動画を見る, 読む]で、Railsアプリケーションでユーザ認証を行うためにdeviseを設定する方法を紹介しました。今回は、前回から引き続いてdeviseをカスタマイズする方法を見ていきます。
前回と同じアプリケーションを使うので、登録、ログイン、ログアウトのページがあり、すでにある程度の認証のしくみができています。
アクセスを制限する
次のステップでは、ログインユーザのみに特定のアクションへのアクセスを制限します。ログインしたユーザだけがプロジェクトを作成、編集、削除できるようにします。このためにProjectsController
を修正しbefore_filter
を追加して、deviseが提供するauthenticate_user!
というメソッドを呼び出すようにします。このメソッドはユーザがログインしているかどうかを確認し、ログインしていない場合はユーザをログインページにリダイレクトします。index
とshow
の各アクションはすべてのユーザから見えるべきなので、:except
パラメータを追加してフィルターからこれらのアクションを除外します。
class ProjectsController < ApplicationController before_filter :authenticate_user!, :except => [:show, :index] def index #rest of class
「新規プロジェクト(New Project)」リンクをクリックすると、ログインしていない場合はログインページにリダイレクトされます。
認証が単純でユーザがログインしているかどうかを確認するだけでよければ、この手法でうまくいくでしょう。より複雑な認証のニーズに対しては、エピソード192 [動画を見る, 読む]で紹介したCanCanのような追加の認証ツールをdeviseと一緒に使用することができます。
Deviseのビューをカスタマイズする
次にdeviseのビューの見え方をカスタマイズする方法を紹介します。すでにサイトの見た目をかなり作り込んでいる場合、deviseが提供するフォームも他のページに合うデザインにしたいでしょう。deviseはRailsエンジンなのでそれ自身がビューを持っていますが、アプリケーションにビューを追加することで簡単にオーバーライドできます。deviseはまたそれらのビューを簡単にコピーするためのジェネレータも提供します。アプリケーションのディレクトリからrails generate devise_views
を実行すると、ビューファイルが自動的に作成されます。
$ rails generate devise_views create app/views/devise create app/views/devise/confirmations/new.html.erb create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions/new.html.erb create app/views/devise/shared/_links.erb create app/views/devise/unlocks/new.html.erb
このコマンドですべてのビューがRailsエンジンであるdeviseからコピーされるので、それらを目的に合うように編集することができます。例えば下のコードは前に見たログインページ用のビューです。
/app/views/devise/sessions/new.html.erb
<h2>Sign in</h2> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <p><%= f.label :email %></p> <p><%= f.text_field :email %></p> <p><%= f.label :password %></p> <p><%= f.password_field :password %></p> <% if devise_mapping.rememberable?-%> <p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p> <% end -%> <p><%= f.submit "Sign in" %></p> <% end %> <%= render :partial => "devise/shared/links" %>
このページを次のように修正します。
<% title "Sign In" %> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <ol class="formList"> <li><%= f.label :email %> <%= f.text_field :email %></li> <li><%= f.label :password %> <%= f.password_field :password %></li> <% if devise_mapping.rememberable?-%> <li><%= f.check_box :remember_me %> <%= f.label :remember_me %></li> <% end %> <li><%= f.submit "Sign in" %></li> </ol> <% end %> <%= render :partial => "devise/shared/links" %>
上のコードで、Ryan Batesのnifty generatorsが提供するtitle
メソッドの呼び出しでヘッダを置き換えました。つまりヘッダのテキストがページのタイトルにも現れます。(この方法はエピソード30 [動画を見る, 読む]で紹介しました。) またページのレイアウトも修正して、フォーム要素がリスト項目として表示されるようにしました。CSSでスタイルを定義することで、これを使って各テキストフィールドのラベルを移動してフィールドの横に表示させることができます。
他のすべてのビューも同じ方法でカスタマイズできるので、アプリケーションの他のページとデザインを合わせることができます。
エラーメッセージをカスタマイズする
Deviseは、何か間違った操作をした場合に表示するエラーメッセージをいくつか持っています。例えば、正しくないメールアドレスやパスワードを入力すると「メールアドレスかパスワードが不正です」というメッセージが表示されます。これらのメッセージはすべてlocaleファイルに保存されているので、簡単に修正したり他の言語に翻訳することが可能です。下のlocaleファイルではdevise.failure.invalid
メッセージを修正しました。
en: errors: messages: not_found: "not found" already_confirmed: "was already confirmed" not_locked: "was not locked" devise: failure: unauthenticated: 'You need to sign in or sign up before continuing.' unconfirmed: 'You have to confirm your account before continuing.' locked: 'Your account is locked.' invalid: 'OH NOES!ERROR IN TEH EMAIL!' invalid_token: 'Invalid authentication token.' timeout: 'Your session expired, please sign in again to continue.' inactive: 'Your account was not activated yet.' sessions: signed_in: 'Signed in successfully.' signed_out: 'Signed out successfully.' #rest of file omitted.
不正なメールアドレスでログインしようとすると、書き換えたメッセージが表示されます。
これでエラーメッセージは対応できましたが、deviseが表示するバリデーション(例えばユーザ登録時に誤った情報を入力した場合など)はどうすればいいでしょうか。
アプリケーションの/config/initializers
ディレクトリの中にdevise.rb
というファイルがあり、このファイルにはdeviseを設定するために使用する多くのオプションが含まれています。これらのオプションについてはドキュメントに詳しい説明があるので、変更したい場合にはどの部分を修正すればいいかが簡単にわかるでしょう。例えば、パスワードの最小文字数を6から4に変えたければ、ファイル中の該当するパートの一番下の行のコメントをはずして、必要な変更を加えます。なんらか変更を加えた後は、アプリケーションにそれを反映させるためにサーバを再起動する必要があります。
# ==> Configuration for :validatable # Range for password length # config.password_length = 6..20
これをさらに進めたければ、バリデーションのデフォルト設定を削除して、自分で書いたコードと置き換えます。User
モデルの中を見ると、アプリケーションが使用しているdeviseモジュールのリストがあり、その一つが:validatable
です。
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :lockable, :timeoutable and :activatable # :confirmable, devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation end
:validatable
モジュールは、登録時にメールアドレスとパスワードのバリデーション処理を行います。この動作を変更したい場合は、このモジュールを削除して自分でバリデーション処理を行うこともできます。しかしvalidatableモジュールはデフォルト設定のままでほとんどの用途に使えるので、今はそのままにしておきます。
ルーティング
次にルートのカスタマイズについて見ていきます。デフォルトでは登録ページは/users/sign_up
にあるのですが、それを/register
に変更します。前回のエピソードではdeviseのジェネレータでdevise_for :users
というルートを作成しました。このルートにいくつかのパラメータを指定して目的に合うようにルートを修正します。
ProjectManage::Application.routes.draw do |map| devise_for :users resources :projects root :to => 'projects#index' end
追加できるパラメータのひとつは、:path_names
で、これを使って登録ページのルートを変更できます。
ProjectManage::Application.routes.draw do |map| devise_for :users, :path_names => { :sign_up => "register" } resources :projects root :to => 'projects#index' end
この修正によって、/users/sign_upにアクセスするとルーティングエラーが発生するようになり、代わりに/users/register
にアクセスさせます。devise_forルートに渡すことができるオプションは他にも多くあり、そのリストをドキュメントで参照できます。
ログイン要件をカスタマイズする
現在のアプリケーションではユーザのログインにメールアドレスとパスワードを用いていますが、メールアドレスの代わりにユーザ名を要求するようにしたければ、それも簡単に実現できます。
まず最初にUser
テーブルにusername
列を追加しますが、これをマイグレーションを作成して行います。
$ rails generate migration add_username_to_users username:string
次にマイグレーションを実行します。
$ rake db:migrate
データベースには1件のユーザしかないので、簡単にRailsコンソールにログインしてそのユーザのusername属性の値を設定します。
$ rails c Loading development environment (Rails 3.0.0.beta2) ruby-1.8.7-p249 > User.first.update_attribute(:username, "eifion") => true
データベースを修正したのでdeviseの設定ファイルも修正します。config.authentication_keys
の行を非コメント化して、値を:email
から:username
に変えます。
config.authentication_keys = [ :username ]
この値が設定されると、deviseはusernameフィールドを認証キーとして使用するようになります。またログインフォームを修正して、メールアドレスの代わりにユーザ名のフィールドを配置します。
<% title "Sign In" %> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <ol class="formList"> <li><%= f.label :username %> <%= f.text_field :username %></li> <li><%= f.label :password %> <%= f.password_field :password %></li> <% if devise_mapping.rememberable?-%> <li><%= f.check_box :remember_me %> <%= f.label :remember_me %></li> <% end %> <li><%= f.submit "Sign in" %></li> </ol> <% end %> <%= render :partial => "devise/shared/links" %>
ユーザ登録フォームも同じように修正する必要があります。またUser
モデルの属性に検証を追加しなくてはいけませんが、ここでは省略します。
サーバを再起動して設定の変更を反映させたら、ログインページにアクセスしてメールアドレスの代わりにユーザ名でログインできます。
deviseのカスタマイズについての今回のエピソードはこれで終わりです。deviseはRailsアプリケーションで認証を行うための優れたツールで、デフォルト設定のままでも十分使用できますが、どのようにでもカスマイズできる柔軟性も持っています。