devise 1.9.3 から 2.0.4へのアップグレード

はじめに

deviseのバージョンを1.9.3から2.0.4に変えたら以下のエラーメッセージがでた。

[DEVISE] Devise.reset_password_within is nil. Please set this value to an interval (for example, 6.hours) and add a reset_password_sent_at field to your Devise models (if they don't have one already).
[DEVISE] devise.registrations.inactive_signed_up in yml files is deprecated, please use devise.registrations.signed_up_but_REASON instead. The default values are:

en:
  devise:
    registrations:
      signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
      signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
      signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'

Deviseは2.0系でいろいろと変更があったらしい。以下を参考に対応させてみる。

カラム(フィールド)の追加

Support for e-mail reconfirmation when it changes. You can benefit from this change by setting Devise.reconfirmable to true and adding an unconfirmed_email column to your Devise models;
How To: Upgrade to Devise 2.0より)

登録情報の変更をした際のメールでの確認をサポートしたとのこと。利用したい場合は Devise.reconfirmable を trueとし、unconfirmed_emailを該当モデル(テーブル)に追加するとのこと。Devise.reconfirmable は 2.x系の config/initializers/devise.rb でデフォルトtrueになっている。

migrationファイルの書き方変更

How To: Upgrade to Devise 2.0 migration schema styleによると、devise 1.x では、どういうことをやりたいのかを記述すると、migration実行時にそれを展開して、対応するフィールドを生成してくれていたけど、2.xからはそれをやめてフィールド名をmigrationファイルに記述する方式になったらしい。

確かに、黒魔術過ぎてどんなフィールドが生成されているのかをdb/schema.rbから逆推理する必要があったものなぁ。

よって、 db/migrate/XXXXX_devise_create_hogehoge.rbを書き換える必要がある。どう書き換えるかは、How To: Upgrade to Devise 2.0 migration schema styleを参照のこと。

db/schema.rbと上記エントリーとの対応を見てみる

1.x対応属性 1.9.3のフィールド名 2.xのフィールド名
t.database_authenticatable t.string "email" t.string :email
t.database_authenticatable t.string "encrypted_password" t.string :encrypted_password
t.recoverable t.string "reset_password_token" t.string :reset_password_token
t.recoverable なし t.datetime :reset_password_sent_at
t.rememberable t.datetime "remember_created_at" t.datetime :remember_created_at
t.trackable t.integer "sign_in_count" t.integer :sign_in_count
t.trackable t.datetime "current_sign_in_at" t.datetime "current_sign_in_at"
t.trackable t.datetime "last_sign_in_at" t.datetime "last_sign_in_at"
t.trackable t.string "current_sign_in_ip" t.string "current_sign_in_ip"
t.trackable t.string "last_sign_in_ip" t.string "last_sign_in_ip"
t.encryptable t.string "password_salt" t.string "password_salt"
t.confirmable t.string "confirmation_token" t.string "confirmation_token"
t.confirmable t.datetime "confirmed_at" t.datetime "confirmed_at"
t.confirmable t.datetime "confirmation_sent_at" t.datetime "confirmation_sent_at"
t.lockable :lock_strategy => :failed_attempts t.integer "failed_attempts"
t.lockable t.string "unlock_token" t.string :unlock_token
t.lockable t.datetime "locked_at" t.datetime :locked_at


t.datetime :reset_password_sent_at に対応するフィールドが見つからない(後述)。

deviseではパスワードのハッシュ化にbcryptを使う場合(デフォルト)は、t.encryptable に対応するフィールドは不要(当該モデルでも :encryptable を指定しないこと)。

config/initializers/devise.rb などで設定する項目の変更

  • Devise.remember_across_browsers is no longer effective. You can simply remove it;
  • Devise.confirm_within was renamed to Devise.allow_unconfirmed_access_for;
  • Devise.stateless_token was removed. If you want to have stateless tokens, simply do config.skip_session_storage << :auth_token in your initializer;

How To: Upgrade to Devise 2.0より)

  • Devise.remember_across_browsers は機能しないので削除する
  • Devise.confirm_within は名称が変わったので Devise.allow_unconfirmed_access_for を使う
    • 私の config/initializers/devise.rb では「config.confirm_within = 2.days」と使われている。なので、「config.allow_unconfirmed_access_for = 2.days」とした
  • Devise.stateless_token は削除されたので、状態を保持しないトークンを利用したい場合は「config.skip_session_storage << :auth_token」と初期化ファイル(config/initializers/devise.rbなど)に書けとのこと。
    • 私の config/initializers/devise.rb では「config.stateless_token = false」というように使われていた。

config/locales/devise.en.yml

How To: Upgrade to Devise 2.0にしたがい、config/locales/devise.en.ymlを編集。私の場合の差分は以下のとおり

% diff devise.en.yml.org devise.en.yml
33c33,35
<       inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
---
>       signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
>       signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
>       signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'

これは、上述のエラーメッセージに対応する話。

[DEVISE] devise.registrations.inactive_signed_up in yml files is deprecated, please use devise.registrations.signed_up_but_REASON instead. The default values are:

en:
  devise:
    registrations:
      signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
      signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
      signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'

render_with_scopeメソッドは削除された

If you also used Devise's render_with_scope method, you may notice that we removed it on 2.0 versions. If you used this method on your controllers (and have properly added your scoped_path) you should now only do a render 'template', because Devise overrides Rails's _prefixes method and thus the correct path is added to the Rails lookup.
How To: Upgrade to Devise 2.0より)

私の場合は使っていなかった。

remember_tokenの削除

Devise now always uses the password salt as basis for the remember token. You can remove the remember_token column from your models and set Devise.use_salt_as_remember_token to true;
How To: Upgrade to Devise 2.0より)

私の場合はremember_tokenはもうなかった。2.x系の Devise.use_salt_as_remember_token は config/initializers/devise.rb でデフォルトtrueになっている。

reset_password_sent_atの追加とDevise.reset_password_withinの設定

Devise now requires you to have a reset_password_sent_at column. Please add it to your Devise models and set Devise.reset_password_within to an interval (like 6 hours);
How To: Upgrade to Devise 2.0より)

上のテーブルの変更で確認したとおり、reset_password_sent_atは新たなカラム(フィールド)らしい。追加の必要あり。Devise.reset_password_within は 2.x系の config/initializers/devise.rb で設定されている。

これは上述のエラーメッセージに対応する話。

[DEVISE] Devise.reset_password_within is nil. Please set this value to an interval (for example, 6.hours) and add a reset_password_sent_at field to your Devise models (if they don't have one already).

新 config/initializers/devise.rb の旧版への対応

困ったときは、新たに devise を作るアプリを生成して、その設定ファイルを編集すれば良い。そこで準備する。Railsでユーザ認証用にdeviseを使うを参考に新deviseで config/initializers/devise.rb を生成する。

% rails new testapp
% cd testapp

Gemfileに以下を追加。

gem 'devise'

config/initializers/devise.rb を生成。

% bundle install
% rails g devise:install
% cp -p config/initializers/devise.rb ~/trunk/config/initializers/devise.rb.2.x
% cd ~/trunk/config/initializers/
% cp -p devise.rb devise.rb.1.x
% mv devise.rb.2.x devise.rb

引き比べながら編集する。

destroy_XXX_session_path() は DELETEメソッドで呼ぶ

1.4ぐらいからそういう設定だったらしいのだけど、config/initializers/devise.rb でGETメソッドで設定していたので、2.xに置き換えるのを機会に対応させた。