User認証を簡単に作れるDevise gemを調べた


##はじめに
Devise gem で出来ること

- webの会員登録のフォームを簡単に作れる(新規登録画面・login画面・etc...)
- sign_in filterなど会員サイトを作るときに必要なhelperが多く用意されている
- facebookなどのominiauthを使うことができる

こんなことが出来るDevise gemを使ってみたい！ってことで調べたもののまとめです。今回は[公式ドキュメン](https://github.com/plataformatec/devise)を調べましたので書いてあることは公式とほぼ変わらないと思います。⬇から早速説明になります。



##deviseを使う
divise3.0はrails3.2以上で動きます。Gemfileに追加してください

```
gem 'devise'
```
そしたらbundleコマンドを使ってinstallしてください

deviseのインストールとGemfileの追加が終わったらgeneratorを走らせる必要があります。

```
rails generate devise:install
```
genaratorはすべてのdeviseの設定オプションをインストールするので一回確認しといてください。これが終わったのならdevise modelを使う準備は完了です。

```
rails generate devise MODEL
```
MODELの部分はユーザーのアプリケーションとして使う名前で置き換えてください。多くの場合はUseやAdminと言ったものが使われます。これはもし既に存在していなければ新規にmodelを作り、deviseのモジュール設定をしてくれます。次に```rake db:migrate```をしてmigrationファイルを作ります。またgeneratorはDevise controllerを示すように config/routes.rbを設定してくれます。
( 注意)既にappを作り始めていたのならやり直してください。さもなければroute helperのエラーやloginできないといったエラーが出るでしょう。

###controllerのfilterとhelpers
DeviseはcontrollerとViewの中で使えるhelperを使うことができます。controllerをset upするときにbefore_filterを加えるだけでuserがauthenticateか判断することが出来ます。

```
before_filter :authenticate_user!
```
userがsign_inしているか判断できるhelperもあります。

```
user_signed_in?
```
現在sign-inしているuserを得るhelperもあります。

```
current_user
```
またuserの活動範囲を確認できます

```
user_session
```
userがsign-inしたり、パスワードを更新したらroot_pathにredirectされます。例えばuser:resourceならばuser_root_pathが存在すればそこに、なければdefaltのroot_pathが使われます。

```
root to: "home#index"
```
また```after_sign_in_path_for```や```after_sign_out_path_for```を使ってredirect先を上書きすることも出来ます。

最後に、mailerの為にurl_optionをすべての環境に設定する必要があります。ここでは"config/environments/development.rb"に設定します。
 
```
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
```

(メモ)もしuserといった devise model を使わずに member を使うのならばhelperはこのようになります

```ruby:
before_filter :authenticate_member!

member_signed_in?

current_member

member_session
```
##Modelの設定
modelの devise method は modules の設定を受けます。たとえば暗号化するアルゴリズムを使いたいのなら

```
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :stretches => 20
```
 :stretchesを除き、:pepper, :encryptor, :confirm_within, :remember_for, :timeout_in, :unlock_in, other valuesで設定することが出来ます。devise:install が使われたときに作られたfileで詳細を見ることが出来ます。

##強調するパラメーター
あなたのviewをカスタマイズするときフォームに新しい特徴を追加することが出来ます。このsanitizationパラメーターはRails4になってmodelからcontrollerに移動しました。Deviseがコレに関する扱いをするものは同様にcontrollerに移動しています。たった３つのactionでどんなパラメーターでもmodelに伝えることが出来ます。それ故sanitizationを必要と知っています。名前とパラメーターの許可はdefaultではこのようになっています。

- sign_in((Devise::SessionsController#new) - emailのような承認キーがある場合のみ許可されます
- sign_up(Devise::RegistrationsController#create) - 証明キーにpasswordとpassword_confirmationを追加するのを許可します
- account_update(Devise::RegistrationsController#update) - 証明キーにpassword, password_confirmation, current_passwordを追加するのを許可します。(the lazy way™)のようなパラメーターを追加で許可したい場合はApplicationControllerに簡単なbefore_filterをすることでできます。

```
class ApplicationController < ActionController::Base
  before_filter :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << :username
  end
end
```
defaltの設定を完全に変えたり、習慣的振る舞いを作るためにpass a blockを作ることも出来ます。

```ruby:
def configure_permitted_parameters
  devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
end
```
もしあなたが複数のDevise　modelを持っているのならmodelごとに異なったsanitizerパラメーターをset upすることができます。その場合、私たちはDevise::ParameterSanitizerから継承し、自身のロジックを追加することを推奨します

```ruby:
class User::ParameterSanitizer < Devise::ParameterSanitizer
  def sign_in
    default_params.permit(:username, :email)
  end
end
```
このときにcontrollerに使うことを設定してください。

```ruby:
class ApplicationController < ActionController::Base
  protected

  def devise_parameter_sanitizer
    if resource_class == User
      User::ParameterSanitizer.new(User, :user, params)
    else
      super # Use the default one
    end
  end
end
```
上記の例では:usernameと:emailの両方を使うためのパラメーターを許可してます。パラメータを設定する愚かでない方法はcustom controllerの上にbefore_filterを定義することによって出来るでしょう。私たちは設定の仕方とcontrollerのカスタマイズ方法をsectionの流れに従って記述しました。

##Viewの設定
私たちはDeviseを使い簡単にuser認証画面を作ることが出来ます。しかし、この方法でなくても自分で作ることも出来ます。Deviseはengineですから、すべてのViewはgemの内側にあります。これらのviewは作り始めを助けれくれますが、後に変えたいと思うでしょう。その場合はgeneratorを使うことでviewをあなたのアプリケーションにコピーしてくれます。

```
rails generate devise:views
```
もしUserやAdminといったDevise modelがあるのならmodelもviewと同じように編集したいと思うでしょう。幸運なことにmodelを改造するのはviewよりも簡単です。``` "config.scoped_views = true"```を "config/initializers/devise.rb"の中に書くだけでいいのです。
これが終わると"users/sessions/new" や "admins/sessions/new"に基づいたviewを持つことができるようになります。 scopeの中にviewが見つからなかったら"devise/sessions/new"というdefaultのviewが使われます。また選んだviewを使うためにgeneratorを使うことも出来ます。

```
rails generate devise:views users
```

##controllerの設定
viewのcustomizationレベルが十分でないのなら、以下の手順ですべてのcontrollerをカスタマイズすることが出来ます。

1,Admins::SessionsController:のようなcustom controller を作ります。

```
class Admins::SessionsController < Devise::SessionsController
end
```
(注意)この例はapp/controller/admins/というディレクトリが既に作られているという前提で進めています

2,使うcontrollerのrouterを書きます

```
devise_for :admins, :controllers => { :sessions => "admins/sessions" }
```

3.controllerに変化を加えると"devise/sessions"のviewが使えなくなるので忘れずに"devise/sessions"を"admins/sessions"にコピーしてください。

Deviseはsign_inが成功したか失敗したかflash messageでuserに伝えることが出来ることを覚えていてください。Deviseはあなたのアプリが適切なに"flash[:notice]"や"flash[:alert]"を呼び出すことを期待しています。すべてのflash hash を出力したり、Deviseのhash keyから:timedout keyを削除することの無いようにしてください。

##Routesの設定
Deviseはdafalutのroutesがあります。もしそれらをカスタマイズする必要あるのならdevise_for methodを使ってください。これは :class_name, :path_prefixといったname_pathを変えることが出来ます。

```ruby:
devise_for :users, :path => "auth", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
```
詳細はdevise_forというdocumentationを確認してください。

もし "/sign_in"だけでなく"/users/sign_in"のようにもっと深く変更を加えたいのならdevise_scopeをrouterに加えてください。

```
devise_scope :user do
  get "sign_in", :to => "devise/sessions#new"
end
```
このように "/sign_in" をするとscopeは:userに限定されます。(注意)devise_scopeは通称なので気をつけてください

###I18n
Deviseのflash message はI18nで使うことが出来ます。

```
en:
  devise:
    sessions:
      signed_in: 'Signed in successfully.'
```
あなたはresourseに基づく固有のmessageをrouteの設定の中に書くことが出来ます

```
en:
  devise:
    sessions:
      user:
        signed_in: 'Welcome user, you are signed in.'
      admin:
        signed_in: 'Hello admin!'
```
Devise mailerはsubject messageに似たモノを使うことが出来ます

```
en:
  devise:
    mailer:
      confirmation_instructions:
        subject: 'Hello everybody!'
        user_subject: 'Hello User! Please confirm your email'
      reset_password_instructions:
        subject: 'Reset instructions'
```
local fileを見ることですべてのメッセージを確認できます。また、どのように翻訳されているか興味があるならこのwikiで確認することが出来ます。

https://github.com/plataformatec/devise/wiki/I18n

##Test helper
Deviseはspec機能を使ったいくつかのhelperを持っています。この機能を使うには test/test_helper.rbfileに以下を付け加える必要があります。

```
class ActionController::TestCase
  include Devise::TestHelpers
end
```
もしあなたがRspecを使っているのならspec/support/devise.rb:の内側に以下を記述して下さい。

```
RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
end
```
これでsign_inとsign_outメソッドを使う準備ができました。これはcontrollerと同じ様な機能を持っています。

```
sign_in :user, @user   # sign_in(scope, resource)
sign_in @user          # sign_in(resource)

sign_out :user         # sign_out(scope)
sign_out @user         # sign_out(resource)
```
あなたは２つのことを心にとどめておく必要があります

1.このhelperはcapybaraなどとは統一することが出来ません機能的なテストだけを使うことが出来ます。そのかわりuser formは既に埋まった状態で使うことが出来ます

2.もしDevise controllerやDeviseを継承したcontrolelrのテストをしたいのならば、使う前にrequestをする必要があります。Deviseはroutesから情報を受け取っているのでこれは不可欠です。しかし、testはrouterを使わないので使うことを明確に示すことが必要と成ります。例えば、user scopeのtestをしたいのならこのようにしてください

```
@request.env["devise.mapping"] = Devise.mappings[:user]
get :new
```

##Omniauth
Deviseはominiauthのサポートを使ったユーザー認証を使用することが出来ます。使うにはconfig/initializers/devise.rbにominiauthの設定を明記してください。

```
config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
```
ominiauthoの機能を使いたい場合は専用のwikiがあるのでこれを良く読んでください

- https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

- [私がまとめたもの](http://qiita.com/sasa0721/items/e8574f9e21ffcaa988c4)

##multiple model設定
Deviseは好きな数だけDevise modelを作ることが出来ます。User model 以外にauthenticationとtime out機能を付け加えたAdmin modelを作りたいのなら以下のようにしてください

```
# Create a migration with the required fields
create_table :admins do |t|
  t.string :email
  t.string :encrypted_password
  t.timestamps
end

# Inside your Admin model
devise :database_authenticatable, :timeoutable

# Inside your routes
devise_for :admins

# Inside your protected controller
before_filter :authenticate_admin!

# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
```
この代わりにDevise generatorを使うだけでも大丈夫です。

このようなmodelは異なったrouteを持つことを覚えておいてください。sign_inやsign_outなどと同じcontrollerを共有して使うことは出来ません。同じactionで異なったroleを使いたい場合は role-based approach　を使うことを勧めます。

##追加情報
#Heroku(重要)
Rails3.1でDeviseをherokuで使いたいのならこのような設定が必要です

```
config.assets.initialize_on_precompile = false
```
その他の潜在的問題についてはコレを読んでください http://guides.rubyonrails.org/asset_pipeline.html