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

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

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

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

Ruby on Rails 6

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

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Q&A

解決済

2回答

3025閲覧

Ruby on Rails6 [Devise, Rspec] コントローラのテストでupdateアクションのパラメータをわたせない

退会済みユーザー

退会済みユーザー

総合スコア0

Devise

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

Ruby on Rails 6

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

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

0グッド

0クリップ

投稿2020/08/02 08:43

編集2020/08/02 12:57

実現したいこと

・パスワード再設定のメールを送信し、メール内のリンクから新たなパスワードを再設定できるようにしたい
・その機能を実装するために、まずはRspecでコントローラのテストをしたい

発生している問題

ブラウザ上でパスワードが再設定できることを確認したのですが、
その流れを再現したコントローラのテストでエラーが出ました。

エラー内容

パスワードの変更を試みたが実際は反映されておらず、
期待した値を返していないという内容(だと思います)。

Failure/Error: expect(user.valid_password?("12345678")).to eq(true) expected: true got: false (compared using ==) Diff: @@ -1 +1 @@ -true +false # ./spec/controllers/passwords_controller_spec.rb:43:in `block (4 levels) in <main>'

テストの内容と試してみたこと

テスト内容とテストデータは下記のとおりです。

user.reload の下に binding.pry を差し込んだところ、変更が反映されていなかったので、
その前の put :update に問題があると思ったのですが、原因を特定できませんでした。

Ruby

1require 'rails_helper' 2 3RSpec.describe Users::PasswordsController, type: :controller do 4 let(:user) { create(:user) } 5 6 describe "updateアクション" do 7 context "パスワード再設定に成功する場合" do 8 it "ルートにリダイレクトする" do 9 @request.env["devise.mapping"] = Devise.mappings[:user] 10 user.confirm 11 put :update, params: { id: user.id, user: { password: "12345678", password_confirmation: "12345678" } } 12 user.reload 13 # ここに binding.pry を入れました 14 expect(user.valid_password?("12345678")).to eq(true) 15 expect(response).to have_http_status "302" 16 expect(response).to redirect_to root_path 17 end 18 end 19 end 20 21end

Ruby

1FactoryBot.define do 2 3 factory :user, class: User do 4 name { 'user' } 5 email { 'user@example.com' } 6 password { '1234567' } 7 end 8 9end

pryで user.password と入力すると、変更前のパスワードである "1234567" が返ってくる状態です。

routes.rb

Ruby

1 Prefix Verb URI Pattern Controller#Action 2 root GET / static_pages#home 3 help GET /help(.:format) static_pages#help 4 about GET /about(.:format) static_pages#about 5 contact GET /contact(.:format) static_pages#contact 6 new_user_session GET /users/sign_in(.:format) users/sessions#new 7 user_session POST /users/sign_in(.:format) users/sessions#create 8 destroy_user_session DELETE /users/sign_out(.:format) users/sessions#destroy 9 new_user_password GET /users/password/new(.:format) users/passwords#new 10 edit_user_password GET /users/password/edit(.:format) users/passwords#edit 11 user_password PATCH /users/password(.:format) users/passwords#update 12 PUT /users/password(.:format) users/passwords#update 13 POST /users/password(.:format) users/passwords#create 14 cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel 15 new_user_registration GET /users/sign_up(.:format) users/registrations#new 16 edit_user_registration GET /users/edit(.:format) users/registrations#edit 17 user_registration PATCH /users(.:format) users/registrations#update 18 PUT /users(.:format) users/registrations#update 19 DELETE /users(.:format) users/registrations#destroy 20 POST /users(.:format) users/registrations#create 21 new_user_confirmation GET /users/confirmation/new(.:format) users/confirmations#new 22 user_confirmation GET /users/confirmation(.:format) users/confirmations#show 23 POST /users/confirmation(.:format) users/confirmations#create 24 sign_in GET /sign_in(.:format) users/sessions#new 25 sign_out DELETE /sign_out(.:format) users/sessions#destroy 26

該当のcontroller

Ruby

1# frozen_string_literal: true 2 3class Users::PasswordsController < Devise::PasswordsController 4 5 def new 6 super 7 end 8 9 def create 10 super 11 end 12 13 def edit 14 super 15 end 16 17 def update 18 super 19 end 20 21 protected 22 23 def after_sending_reset_password_instructions_path_for(resource_name) 24 super(resource_name) 25 end 26 27 def after_resetting_password_path_for(resource) 28 super(resource) 29 end 30 31end 32

該当のview

<% provide(:title, "パスワード再設定") %> <h3>新しいパスワードを設定してください</h3> <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <%= f.hidden_field :reset_password_token %> <div class="field"> <%= f.label :password, "新しいパスワード" %><br /> <% if @minimum_password_length %> <em>パスワードは<%= @minimum_password_length %>文字以上です</em><br /> <% end %> <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation, "確認用パスワード" %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "保存" %> </div> <% end %> <%= render "devise/shared/links" %>

確認したこと

controllerとviewはデフォルトで使用しており、またブラウザでは正常に作動したので
単にテストの update アクションで値を正しく渡せていないだけだと思ったのですが、
本当の原因がわかりませんでした。

テストの書き方は、こちらのサイトを参考にしています。

質問に不備がある場合は遠慮なく伝えていただけると幸いです。
どうぞよろしくお願いします。

補足情報(FW/ツールのバージョンなど)

ruby 2.7.1
Rails 6.0.3.2

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

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

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

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

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

guest

回答2

0

ベストアンサー

自己解決できたので、その方法を記載します。

今回のテストがパスしない原因は、やはりトークンがパラメータとして渡されていないからで、
そこを定義すればパスしました。

上記のテスト内に、下記のトークンを定義し、
@raw = user.send_reset_password_instructions

下記のように値を渡してあげるとパスします。
put :update, params: { user: { reset_password_token: @raw, password: "12345678", password_confirmation: "12345678" } }

そもそも今回の問題の一番の原因は、
私がGithubのtestに関する部分を確認していなかったことにあります^^;
もっとソースコードを注意して読まないとだめですね。勉強になりました。

ご協力いただいたwinterboumさん、この度はどうもありがとうございました!
これにて質問を閉めさせていただきます。

投稿2020/08/03 22:30

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

user.password で値が返ってくるのが不思議です。
database users テーブルに password カラムが作られていたりしてませんか。

投稿2020/08/02 09:27

winterboum

総合スコア23567

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

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

退会済みユーザー

退会済みユーザー

2020/08/02 12:52 編集

早速のご返信ありがとうございます! rails consoleからカラムを調べたのですが、下記の通りpasswordカラムはありませんでした。 [1] pry(main)> User.column_names => ["id", "name", "profile", "email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "confirmation_token", "confirmed_at", "confirmation_sent_at", "unconfirmed_email", "created_at", "updated_at"] ちなみにpasswordだけでなくencrypted_passwordも出せます。 [1] pry(#<RSpec::ExampleGroups::UsersPasswordsController::Update::Nested_2>)> user.password => "1234567" [2] pry(#<RSpec::ExampleGroups::UsersPasswordsController::Update::Nested_2>)> user.encrypted_password => "$2a$04$3n2pNfzAfp78nL.rRQCiduFNRdldmhh/CaVtlnRCAxcnpiMRRuKJi" この現象も何か関係していると考えられるでしょうか?
winterboum

2020/08/02 22:38

user.encrypted_password はでて良いのですが、それupdateの前後で変わっているかなぁ、、、 controllerの方にpry仕掛けて、paramsなど確認してみてください。
退会済みユーザー

退会済みユーザー

2020/08/03 17:19

winterboumさん ご返信ありがとうございます。 調べた結果ですが、対象のユーザーを検索できていないのが原因かもしれません。 というのもupdateアクションが開始される際に、パスワード再設定のメールに仕込んだトークンを使ってユーザーを検索しているのですが、pryでその処理の後を確認してみると、ユーザーを検索できていなかったからです。 ブラウザ上とテストで更新の結果が異なるのは、テストではトークンをわたす処理を再現できていないからかもしれません。 まだ確認段階ですが、わかったことがあればまた追記します。
退会済みユーザー

退会済みユーザー

2020/12/26 09:08 編集

自己解決できたので、その方法を記載します。 今回のテストがパスしない原因は、やはりトークンがパラメータとして渡されていないからで、 そこを定義すればパスしました。 上記のテスト内に、下記のトークンを定義し、 @raw = user.send_reset_password_instructions 下記のように値を渡してあげるとパスします。 put :update, params: { user: { reset_password_token: @raw, password: "12345678", password_confirmation: "12345678" } } そもそも今回の問題の一番の原因は、 私がGithubのtestに関する部分を確認していなかったことにあります^^; もっとソースコードを注意して読まないとだめですね。勉強になりました。 ご協力いただいたwinterboumさん、この度はどうもありがとうございました! これにて質問を閉めさせていただきます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問