質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

854閲覧

railsのdeviseでログインとバリデーションが両立できない

gomes_2222

総合スコア90

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2023/02/27 08:02

実現したいこと

railsで会員登録機能を実装してます。

deviseを使いました。
ユーザー情報の編集機能を付け足そうとしたらエラーに遭遇しました。

前提

ここに質問の内容を詳しく書いてください。
(例)
TypeScriptで●●なシステムを作っています。
■■な機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

ログイン時、以下のエラー
確かにアカウント作成時のパスワードの最小文字制限としてバリデーションを実装しました。
しかし、アカウント作成、アカウント情報更新時のみ動くバリデーションとして想定しており、ログイン時に動くことは想定してません。

ちなみに、ログイン時に入力したパスワードも6文字以上なのですが、なぜこのエラーが出るのか謎です。

ActiveRecord::RecordInvalid in DeviseTokenAuth::SessionsController#create Validation failed: Password is too short (minimum is 6 characters), Password is invalid

該当のソースコード

model

1class User < ActiveRecord::Base 2 devise :database_authenticatable, :registerable, 3 :recoverable, :rememberable, :validatable 4 include DeviseTokenAuth::Concerns::User 5 6 VALID_PASSWORD = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i 7 validates :password, 8 format: { with: VALID_PASSWORD }, 9 on: :create 10 11 validates :password, 12 length: { in: 6..128}, 13 format: { with: VALID_PASSWORD }, 14 on: :update 15 16end

contoller

1class Auth::SessionsController < ApplicationController 2 def index 3 if current_user 4 render json: { is_login: true, data: current_user } 5 else 6 render json: { is_login: false, message: “ユーザーが存在しません” } 7 end 8 end 9end

rspec

1subject { post(‘/auth/sign_in’, params: params) } 2 context “メールアドレス、パスワードが正しいとき” do 3 let(:current_user) { FactoryBot.create(:user) } 4 let(:params) { { email: current_user.email, password: current_user.password } } 5 it “ログインできる” do 6 subject 7 expect(response).to have_http_status(200) 8 end

factorybot

1FactoryBot.define do 2 factory :user do 3 name { ‘test_user’ } 4 email { test@example.com”} 5 password { ‘testpass1234’ } 6 password_confirmation { password } 7 end 8end

試したこと

modelを以下のように書いてみたところ、ログインが正常にできたので、updateと書くのが悪さをしていると思ってはいますが、
なぜそうなるのかがわかりません。

model

1class User < ActiveRecord::Base 2 devise :database_authenticatable, :registerable, 3 :recoverable, :rememberable, :validatable 4 include DeviseTokenAuth::Concerns::User 5 6 VALID_PASSWORD = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i 7 validates :password, 8 format: { with: VALID_PASSWORD }, 9 on: :create 10 11 validates :password, 12 length: { in: 6..128}, 13 format: { with: VALID_PASSWORD }, 14 on: :create 15 16end

聞きたいこと

・なぜ、ログインを実行する際に

on: :update

と記述したバリデーションが起動するのか?

・ログインするさいは、emailとパスワードを入力します。
この時入力するパスワードはもちろん6文字以上なのですが、なぜ「6文字未満はNG」のバリデーションに引っかかるのか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuma.inaura

2023/02/27 11:56

テストでリクエストに指定する params が間違ってたりしませんか
guest

回答1

0

ベストアンサー

面白い問題ですね!
DeviseTokenAuthを使用したことがないため仮設の域を出ない旨了承いただけますと幸いです。


Q1.なぜon::updateのバリデーションが起動するのか?
以下の理由よりDeviseTokenAuthの仕様によるものかと考えられます。

  • DeviseTokenAuthの無いただのDeviseであれば提示されたバリデーションでログインできる
  • エラー文にDeviseTokenAuth::SessionsControllerとある

実際にDeviseTokenAuth::SessionsControllerの記述を見ると、createアクション内にcreate_and_assign_tokenの記述があります(30行目)。
create_and_assign_tokenの定義式(137行目下)を見ると@resource.save!の記述があるので、この記述によりusersテーブルの更新処理が動き、結果on::updateが発動したのではないかと考えられます。
(on::updateはレコード更新時に発動するといった意味であるため)


Q2.なぜ「6文字未満はNG」のバリデーションに引っかかるのか?
もしQ1で挙げた通り@resource.save!でエラーになっている場合、「ログイン画面で入力したpassword」ではなく「データベースに保存されたユーザーのpassword」に対してバリデーションが働いていることで引っかかっているかと考えられます。
(@resourceにはデータベースに保存されているユーザーが格納されるため)

deviseの機能としてデータベースから取得したユーザーはpassword属性の値がnilになりますので、それにより6文字制限のパスワードエラーが発生していることが推測されます。

投稿2023/02/27 11:57

miwa0123

総合スコア22

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miwa0123

2023/02/27 12:02 編集

rails cで以下を行うと「データベースに保存されているユーザー」に対してバリデーションチェックをした際に引っかかることを確認できますのでお試しいただければ👍 ``` @user = User.find(1) @user.valid? @user.errors ```
gomes_2222

2023/03/03 06:00

とても参考になりました。 ありがとうございます! DeviseTokenAuthにあわせて考え直さないといけないですね。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問