Devise の ID/pass 認証で email じゃない field を採用するときに undefined method `email' for an instance of User が出る
— Diary — 2 min read
結論: :validatable は設定できない
久しぶりの更新がニッチで使い古された小ネタですいません・・.
Rails アプリで「そういえば email に限らない ID を使ったログインてどう作るんだろ」と思って試してちょっとハマったのでメモです.
authentication_keys による ID field の差し替えをしているのに,設定後にユーザ追加しようとして以下のエラーになっていました.
irb(main):001* User.create!(irb(main):002* login_id: "youknow",irb(main):003* password: "password",irb(main):004> )(irb):1:in `<main>': undefined method `email' for an instance of User (NoMethodError)
:database_authenticatable
といっしょに :validatable
を指定していたのが原因というポカミスでした.
(前提) devise で email じゃない ID を有効にする
おさらいですが,devise で ID として扱われる email を差し替える方法です.
email でなく :login_id にしてみます.
create_table "users", force: :cascade do |t| t.string "login_id", null: false t.string "encrypted_password", null: false t.timestamps
t.index ["login_id"], name: :index_login_id_on_usersend
class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
基本的には,devise.rb で authentication_keys を切り替えてやればいいはず.
試してませんが,User 以外にも devise を有効にしたい model がある場合は,ID を差し替えたい model(例えば User)側で devise :database_authenticatable, authentication_keys: [:hogehoge]
とかにすればいいと思います.
cat config/initializers/devise.rb | grep login_id config.authentication_keys = [:login_id] config.case_insensitive_keys = [:login_id] config.strip_whitespace_keys = [:login_id]
:validatable は email が前提
validatable の実装見れば一目瞭然なんですが,email/password 前提の実装なのでした.
module Validatable (snip) def self.included(base) ... base.class_eval do # email_required? == true なので必ず presence の検証がなされエラーになる validates_presence_of :email, if: :email_required? validates_uniqueness_of :email, allow_blank: true, case_sensitive: true, if: :devise_will_save_change_to_email? validates_format_of :email, with: email_regexp, allow_blank: true, if: :devise_will_save_change_to_email? ... end ... def email_required? true end ... end end
https://github.com/heartcombo/devise/blob/main/lib/devise/models/validatable.rb
参考:
https://kossy-web-engineer.hatenablog.com/entry/2020/11/14/102434