Devise ではメールアドレスとパスワードを使ってサインインするのがデフォルト。
メールアドレスではなくユーザー名、それとパスワードでサインインしたい場合はどうすればいいか? Devise が呼び出すモデルとコントローラーのメソッドを上書きするしかない。
やったことをメモしておく。
ユーザー名を保存する列を追加
すでに users テーブルを作っていたので、users テーブルに列を追加する。
$ rails generate migration AddUsernameToUsers
マイグレーションファイルの中身は次の通り。
class AddUsernameToUsers < ActiveRecord::Migration def change add_column :users, :username, :string, null: false, default: "" add_index :users, :username, unique: true end end
あとはマイグレーションを実行。
認証のキーにユーザー名を使えるようにモデルを修正
ユーザー名を使ってサインインするのは User だけなので、 User クラスで認証に使うキーを指定する。
class User < ActiveRecord::Base # 認証で使うキーを指定 devise :database_authenticatable, :trackable, :validatable, authentication_keys: [:username] # ユーザー名で検索 def self.find_first_by_auth_conditions(warden_conditions) conditions = warden_conditions.dup if username = conditions.delete(:username) where(conditions).where(username: username).first else where(conditions).first end end # 登録時に email を不要にする def email_required? false end def email_changed? false end end
ユーザー名を認証時のパラメータとして使えるようにコントローラーを修正
ユーザー名が Strong Parameters ではじかれないように対策が必要。
class ApplicationController < ActionController::Base before_filter :configure_permitted_parameters, if: :devise_controller? # ...省略... protected def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:subdomain, :username, :email, :password, :password_confirmation) } devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:subdomain, :username, :email, :password, :remember_me) } end end
ユーザー名を入力できるようにカスタムビューを作成
ユーザー名とパスワードでサインインするのは User だけなので、 異なるビューを使えるように initializers/devise.rb で設定する。
Devise.setup do |config| # ...省略... config.scoped_views = true end
ビューを生成。
$ rails generate devise:view users
app/views/users/sessions/new.html.erb を修正し、ユーザー名とパスワードを入力できるようにする。
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "form-signin", role: "form" }) do |f| %> <h2 class="form-signin-heading"> サインイン </h2> <%= f.text_field :username, class: "form-control", placeholder: "ユーザー名" %> <%= f.password_field :password, autocomplete: "off", class: "form-control", placeholder: "パスワード" %> <%= f.submit "サインイン", data: { disable_with: "サインイン中..." }, class: "btn btn-lg btn-primary btn-block" %> <% end %>
なお、今回作っているアプリは「ユーザー登録を行うのは管理者ユーザーのみ」という仕様だったので、 ユーザー名とパスワードでのサインアップは省いた。