Railscasts#235で作成したDevise入りアプリケーション。
これをカスタマイズして、
- OmniAuthでユーザー登録した場合はemailの入力は不要にする
- OmniAuthで登録したユーザーが自分のユーザー情報を編集したとき、emailフォームを空白にしても、uniqueバリデーションでアップデートを拒否されないようにする
以上の2つを満たすようにしたい。
なお現在Deviseのアップデートに伴い、より簡単になったOAuth対応機能を使ったRailscasts#235revisedが公開されている。が、アプリケーション作成の際に旧バージョンのRailscastsを参考にしたので、今さら変えられない。
- インデックスを消す
- email_required?をオーバーライド
- emailカラムのデフォルト変更
の順番で作業を行う。
インデックスを消す
Deviseで
$ rails g devise user
したときにできる20130101111111_devise_create_users.rbには、
add_index :users, :email, :unique => true
というインデックス追加を含んでいる。
このインデックスを残したままだとまずいので、まずこれを消す。
$ rails g migration remove_index_email_from_users
でできた20130514071534_remove_index_email_from_users.rbを
class RemoveIndexEmailFromUsers < ActiveRecord::Migration
def up
remove_index :users, :email
end
def down
add_index :users, :email, unique: true
end
end
と書きかえる。
$ rake db:migrate
でマイグレーション適用。インデックス削除ができたことはdb/schema.rbで確認できる。
email_required?をオーバーライド
email_required?をオーバーライドすれば、devise内のemailのバリデーション設定をカスタマイズできる。
email_required? メソッドは、deviseの/lib/devise/models/validatable.rbにある、
validates_presence_of :email, :if => :email_required?
で、emailのvalidates_presence_ofを行うかの判定に使われている。
そのコードはこちら。
https://github.com/plataformatec/devise/blob/c179cef365f7188c91cbbc3db924a9f1f9563c3c/lib/devise/models/validatable.rb#L29
なので、email_required?の返り値をfalseにすると、emailのvalidates_presence_ofバリデーションを行わない。
具体的にどうすればよいかというと、
def email_required?
(authentications.empty? || !email.blank?) && super
end
とuserモデルに書く。これで、email_required? メソッドをオーバーライドできる。条件文が複雑なので、整理すると、
Emailの存在が必要な場合
- ユーザーがOAuthのauthenticationsを持っていないとき
- 空白ではないEmailを入力したとき
Emailの存在が不要な場合
- ユーザーがOAuthのauthenticationsを持っている
- かつ、Emailが空白かそもそもnilのとき
となる。
emailカラムのデフォルト変更
DBスキーマのemailカラムは
t.string "email", :default => "", :null => false
となっている。デフォルトで空白、nullは許可しない状態。
デフォルトでnullにして、nullを許可したい。
$ rails g migration change_email_default
でmigrationファイルを作って、
class ChangeEmailDefault < ActiveRecord::Migration
def up
change_column :users, :email, :string, null: true
change_column_default :users, :email, nil
end
def down
change_column :users, :email, :string, null: false
change_column_default :users, :email, ""
end
end
と書きかえる。で、
$ rake db:migrate
すれば、
t.string "email"
と、nilを許可して、デフォルトをnilにできた。
あとは、サーバを再起動すれば、OAuthで登録したユーザーに関してはemail入力が不要になる。もうuniqueバリデーションで弾かれることはない。