Deviseでユーザー認証

目的

Deviseでユーザー認証を行い、CanCanで権限管理をする。
新規ユーザーは、管理者のみ作成可能
E-MailをユーザーIDとして利用しない

インストール

Gemfileに追記

# Authentication
gem 'devise'

group :development do
  gem 'erb2haml'
  gem 'haml2slim'
end

gemをインストール

bundle install

Devise設定

Deviseインストール

rails g devise:install
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here 
     is an example of default_url_options appropriate for a development environment 
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { :host => 'localhost:3000' }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root :to => "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying Rails 3.1 on Heroku, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

===============================================================================

インストール時に表示されたメッセージに従って、設定

  • config/environments/development.rb に記述を追加
config.action_mailer.default_url_options = { :host => 'localhost:3000' }

ログイン後は、config/routes.rbに記載したrootに戻ってくるとのことだからrootを設定

  • config/routes.rb
root :to => "home#index"

Twitter Bootstrapですでに記述済み

application.html.hamlにnoticeとalertを設定

  • app/views/layouts/application.html.slim
    • yieldの上部に記述
            p.notice= notice
            -if alert.present?
              p.alert= alert
  • 以下の記述だと、枠が表示される
            p.notice= notice
            p.alert= alert
  • config/application.rb
config.assets.initialize_on_precompile = false

認証用モデルを作成

rails g devise user user_id:string user_name:string
      invoke  active_record
      create    db/migrate/20120611131651_devise_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
      insert    app/models/user.rb
       route  devise_for :users

ビューを生成

rails g devise:views

_links.erbをリネーム

mv app/views/devise/shared/_links.erb app/views/devise/shared/links.html.erb

※後述のhaml変換が行われないため

生成されたビューはerbなので、hamlに変換する

rake haml:convert_erbs

hamlをslimに変換する

for i in `find app/views/devise -name '*.haml'` ; do haml2slim $i ${i%haml}slim ; done

erb,hamlを削除

for i in `find app/views/devise -name '*.erb'` ; do rm $i ; done
for i in `find app/views/devise -name '*.haml'` ; do rm $i ; done

links.html.slimをリネーム

mv app/views/devise/shared/links.html.slim app/views/devise/shared/_links.slim

Userモデルを以下のように変更

  • ./app/models/user.rb
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :rememberable, :trackable, :validatable,
         :authentication_keys => [:user_id]

  # Setup accessible (or protected) attributes for your model
  attr_accessible :user_name, :user_id, :email, :password, :password_confirmation, :remember_me
  # attr_accessible :title, :body

  def email_required?
    false
  end
end

マイグレーションファイル一部修正

  • ./db/migrate/20120611131651_devise_create_users.rb

修正前:

add_index :users, :email,                :unique => true

修正後:

add_index :users, :user_id,              :unique => true

マイグレーション

rake db:migrate

ルーティング設定に以下が追記されていることを確認

  • config/routes.rb
devise_for :users

devise_for :users, :path => "auth", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'sign_up' }

に変更

確認

サーバー起動

rails s

以下にアクセス
http://localhost:3000/auth/login

Deviseの簡単な使い方

コントローラーの最初などに埋め込む
認証済みかどうかチェックし、認証していない場合はログイン画面へリダイレクトされる

before_filter :authenticate_user!

現在ユーザーがログイン中か否か

user_sined_in?

ログインするためのパス

new_user_session_path

ログアウトするためのパス

destroy_user_session_path

ログイン済みのユーザーオブジェクト

current_user

おまけ

http://localhost:3000/login
↓リダイレクト
http://localhost:3000/auth/login

  • config/routes.rb
match "login", :to => redirect("/auth/login"), :as => "login"

日本語化

  • config/application.rb
config.i18n.default_locale = :ja

ja.ymlをダウンロード

wget https://raw.github.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -P ./config/locales/

devise.ja.ymlをダウンロード ( http://pastebin.com/LvFTDgHj )

wget http://pastebin.com/raw.php?i=LvFTDgHj -O ./config/locales/devise.ja.yml
  • config/locales/devise.ja.yml をちょっと修正
ja:
  "Sign in": "ログイン"
  "Registration": "ユーザー登録"
  "Sign up": "ユーザー登録"
  "Update": "更新"
  "Forgot your password?": "パスワード忘れはこちら"
  "Send me reset password instructions": "パスワード再発行"
  "Resend confirmation instructions": "パスワード再発行"
  "Didn't receive confirmation instructions?": "確認メールの再送信"
  "Didn't receive unlock instructions?": "アカウント凍結解除メールの再送信"

  errors:
    messages:
      expired: "は期限切れになりました。登録し直してください。"
#      expired: "has expired, please request a new one"
      not_found: "は見つかりませんでした"
#      not_found: "not found"
      already_confirmed: "は既に登録済みです"
#      already_confirmed: "was already confirmed"
      not_locked: "は凍結されていません"
#      not_locked: "was not locked"
      not_saved:
        one: "%{resource}にエラーが発生しました。"
#        one: "1 error prohibited this %{resource} from being saved:"
        other: "%{resource}に%{count}個のエラーが発生しました。"
#        other: "%{count} errors prohibited this %{resource} from being saved:"

  devise:
    failure:
      already_authenticated: 'すでにログインしています。'
#      already_authenticated: 'You are already signed in.'
      unauthenticated: 'ログインしてください。'
#      unauthenticated: 'You need to sign in or sign up before continuing.'
      unconfirmed: '本登録を行ってください。'
#      unconfirmed: 'You have to confirm your account before continuing.'
      locked: 'あなたのアカウントは凍結されています。'
#      locked: 'Your account is locked.'
      invalid: 'ユーザーIDかパスワードが違います。'
#      invalid: 'メールアドレスかパスワードが違います。'
#      invalid: 'Invalid email or password.'
      invalid_token: '認証キーが不正です。'
#      invalid_token: 'Invalid authentication token.'
      timeout: 'セッションがタイムアウトしました。もう一度ログインしてください。'
#      timeout: 'Your session expired, please sign in again to continue.'
      inactive: 'アカウントがアクティベートされていません。'
#      inactive: 'Your account was not activated yet.'
    sessions:
      signed_in: 'ログインしました。'
#      signed_in: 'Signed in successfully.'
      signed_out: 'ログアウトしました。'
#      signed_out: 'Signed out successfully.'
    passwords:
      send_instructions: 'パスワードのリセット方法を数分以内にメールでご連絡します。'
#      send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
      updated: 'パスワードを変更しました。'
#      updated: 'Your password was changed successfully. You are now signed in.'
      updated_not_active: 'パスワードを変更しました。'
#      updated_not_active: 'Your password was changed successfully.'
      send_paranoid_instructions: "データベースにメールアドレスが存在する場合は、パスワード変更ページへのリンクがあるメールをお送りします。"
#     send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail"
    confirmations:
      send_instructions: '登録方法を数分以内にメールでご連絡します。'
#      send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
      send_paranoid_instructions: 'データベースにメールアドレスがあった場合は、登録方法を数分以内にメールでご連絡します。'
#     send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.'
      confirmed: 'アカウントを登録しました。'
#      confirmed: 'Your account was successfully confirmed. You are now signed in.'
    registrations:
      signed_up: 'アカウントを登録しました。'
#      signed_up: 'アカウント登録を受け付けました。確認のメールをお送りします。'
#      signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
      inactive_signed_up: 'アカウント登録を受け付けました。%{reason}ため、ログインできませんでした。'
#      inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
      updated: 'アカウントを更新しました。'
#      updated: 'You updated your account successfully.'
      destroyed: 'アカウントを削除しました。またのご利用をお待ちしております。'
#      destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
      reasons:
        inactive: 'アクティベートされていない'
#        inactive: 'inactive'
        unconfirmed: '確認されていない'
#        unconfirmed: 'unconfirmed'
        locked: '凍結されている'
#        locked: 'locked'
    unlocks:
      send_instructions: 'アカウントの凍結解除方法を数分以内にメールでご連絡します。'
#      send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
      unlocked: 'アカウントを凍結解除しました。'
#      unlocked: 'Your account was successfully unlocked. You are now signed in.'
      send_paranoid_instructions: 'アカウントが存在した場合は、アカウントの凍結解除方法を数分以内にメールでご連絡します。'
#      send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.'
    omniauth_callbacks:
      success: '%{kind}アカウントから承認されました。'
#      success: 'Successfully authorized from %{kind} account.'
      failure: '"%{reason}"であるため、%{kind}から承認されませんでした。'
#      failure: 'Could not authorize you from %{kind} because "%{reason}".'
    mailer:
      confirmation_instructions:
        subject: 'アカウントの登録方法'
#        subject: 'Confirmation instructions'
      reset_password_instructions:
        subject: 'パスワードの再設定'
#        subject: 'Reset password instructions'
      unlock_instructions:
        subject: 'アカウントの凍結解除'
#        subject: 'Unlock Instructions'
  • config/locales/attributes.ja.yml
ja:
  activerecord:
    attributes:
      user:
        email: 'メールアドレス'
        password:  'パスワード'
        password_confirmation:  'パスワード(再入力)'
        remember_me:  'ログイン状態を保持する
      post:
        title: '題名'
        body:  '内容'
  • config/locales/helpers.ja.yml
ja:
  helpers:
    submit:
      create: "登録する"
      update: "更新する"
      submit: "保存する"
    label:
      user:
        email: "メールアドレス"
        password: "パスワード"
  title:
    new: '新規投稿'
  • config/locales/views.ja.yml
ja:
  devise:
    sessions:
      new:
        user_id: "ユーザーID"
        password: "パスワード"
        remember_me: "ログイン状態を保持する"
    registrations:
      new:
        user_name: "ユーザー名"
        user_id: "ユーザーID"
        password: "パスワード"
        password_confirmation: "パスワード(再入力)"
      edit:
        edit: "登録情報の修正"
        user_name: "ユーザー名"
        user_id: "ユーザーID"
        password: "変更後のパスワード"
        leave_blank_if_you_dont_want_to_change_it: "(変更の必要がなければ,空にしておいて下さい。)"
        password_confirmation: "確認のためもう一度パスワードを入力して下さい。"
        current_password: "現在のパスワード"
        we_need_your_current_password_to_confirm_your_changes: "(認証のため現在のパスワードを入力して下さい。)"
        remove_account: "アカウントを削除"
        confirm: "本当によろしいですか?"
        back: "戻る"

ログイン画面の日本語化

  • app/views/devise/sessions/new.html.slim
= twitter_bootstrap_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
  = f.inputs t 'Sign in', :class => 'sign_in' do
    = f.text_field :user_id, t(".user_id")
    = f.password_field :password, t(".password")
    - if devise_mapping.rememberable?
      = f.check_box :remember_me, t(".remember_me")
    = f.actions do
      = f.submit t "Sign in"
  • app/views/devise/registrations/new.html.slim
= twitter_bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
  = devise_error_messages!
  = f.inputs t 'Sign up', :class => 'sign_in' do
    = f.text_field :user_name, t(".user_name")
    = f.text_field :user_id, t(".user_id")
    = f.password_field :password, t(".password")
    = f.password_field :password_confirmation, t(".password_confirmation")
    = f.actions do
      = f.submit t "Sign up"
  • app/views/devise/shared/_links.slim
- if controller_name != 'sessions'
  = link_to "#{t "Sign in"}", new_session_path(resource_name)
  br/
- if devise_mapping.registerable? && controller_name != 'registrations'
  = link_to "#{t "Sign up"}", new_registration_path(resource_name)
  br/
- if devise_mapping.recoverable? && controller_name != 'passwords'
  = link_to "#{t "Forgot your password?"}", new_password_path(resource_name)
  br/
- if devise_mapping.confirmable? && controller_name != 'confirmations'
  = link_to "#{t "Didn't receive confirmation instructions?"}", new_confirmation_path(resource_name)
  br/
- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
  = link_to "#{t "Didn't receive unlock instructions?"}", new_unlock_path(resource_name)
  br/
- if devise_mapping.omniauthable?
  - resource_class.omniauth_providers.each do |provider|
    = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider)
    br/