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

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

新規登録して質問してみよう
ただいま回答率
85.47%
Ruby on Rails 5

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

Q&A

解決済

1回答

2775閲覧

Railsチュートリアル 第12章でPassword Resetフォームが開けない(password_resets/editが動作しない)

K2_Yoshiko

総合スコア4

Ruby on Rails 5

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

0グッド

0クリップ

投稿2020/02/09 05:23

前提・実現したいこと

Railsチュートリアル第12章 3節「パスワードを再設定する」へ取り組む中で、調べてみても解決できないエラーに遭遇したので質問いたします。

12.3.1.1の演習中に、Railsサーバーのログからパスワードリセット用のメールリンクを探してアクセスしたところ、ルート画面に飛ばされてしまい、パスワードリセットのフォームが表示されない状況です。

teratailの同じエラーを出している記事も試してみましたがうまく行かず、12章や11章までさかのぼってコードをコピペしても状況は変わりませんでした。

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

####Railsサーバーのログ(再設定用メールのリンクにアクセスしたとき)

Started GET "/password_resets/75n959ghPFmrlJktckBrBg/edit?email=example%40railstutorial.org" for 49.104.15.211 at 2020-02-09 04:57:12 +0000 Cannot render console from 49.104.15.211! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by PasswordResetsController#edit as HTML Parameters: {"email"=>"example@railstutorial.org", "id"=>"75n959ghPFmrlJktckBrBg"} User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "example@railstutorial.org"], ["LIMIT", 1]] Redirected to https://93bfd3f26b434df4a4e3ab34c29fdd54.vfs.cloud9.us-east-2.amazonaws.com/ Filter chain halted as :valid_user rendered or redirected Completed 302 Found in 78ms (ActiveRecord: 0.8ms) Started GET "/" for 49.104.15.211 at 2020-02-09 04:57:12 +0000 Cannot render console from 49.104.15.211! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by StaticPagesController#home as HTML Rendering static_pages/home.html.erb within layouts/application Rendered static_pages/home.html.erb within layouts/application (2.8ms) Rendered layouts/_rails_default.html.erb (39.5ms) Rendered layouts/_shim.html.erb (0.4ms) Rendered layouts/_header.html.erb (0.7ms) Rendered layouts/_footer.html.erb (0.4ms) Completed 200 OK in 49ms (Views: 48.5ms | ActiveRecord: 0.0ms)

####12.3.3「パスワードの再設定をテストする」の実行結果

[1] guard(main)> 05:08:07 - INFO - Run all 05:08:07 - INFO - Running: all tests Running via Spring preloader in process 13101 Started with run options --seed 18780 FAIL["test_password_resets", PasswordResetsTest, 1.5618210910006383] test_password_resets#PasswordResetsTest (1.56s) expecting <"password_resets/edit"> but rendering with <[]> test/integration/password_resets_test.rb:40:in `block in <class:PasswordResetsTest>' 45/45: [=======================================================================================] 100% Time: 00:00:01, Time: 00:00:01 Finished in 1.84732s 45 tests, 200 assertions, 1 failures, 0 errors, 0 skips /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/guard-2.13.0/lib/guard/jobs/pry_wrapper.rb:279: warning: method Pry#input_array is deprecated. Use Pry#input_ring instead

該当のソースコード

####PasswordResetsのコントローラー

Ruby

1class PasswordResetsController < ApplicationController 2 3 before_action :get_user, only: [:edit, :update] 4 before_action :valid_user, only: [:edit, :update] 5 before_action :check_expiration, only: [:edit, :update] 6 7 def new 8 end 9 10 def create 11 @user = User.find_by(email: params[:password_reset][:email].downcase) 12 if @user 13 @user.create_reset_digest 14 @user.send_password_reset_email 15 flash[:info] = "Email sent with password reset instructions" 16 redirect_to root_url 17 else 18 flash.now[:danger] = "Email address not found" 19 render 'new' 20 end 21 end 22 23 def edit 24 end 25 26 def update 27 if params[:user][:password].empty? 28 @user.errors.add(:password, :blank) 29 render 'edit' 30 elsif @user.update_attributes(user_params) 31 log_in @user 32 flash[:success] = "Password has been reset." 33 redirect_to @user 34 else 35 render 'edit' 36 end 37 end 38 39 private 40 41 def user_params 42 params.require(:user).permit(:password, :password_confirmation) 43 end 44 45 # beforeフィルター 46 47 def get_user 48 @user = User.find_by(email: params[:email]) 49 end 50 51 # 正しいユーザーかどうかの確認 52 def valid_user 53 unless @user && @user.activated? && 54 @user.authenticated?(:reset, params[:id]) 55 redirect_to root_url 56 end 57 end 58 59 # パスワード再設定の有効期限を確認 60 def check_expiration 61 if @user.password_reset_expired? 62 flash[:danger] = "Password reset has expired." 63 redirect_to new_password_reset_url 64 end 65 end 66end 67

####Userモデル

Ruby

1class User < ApplicationRecord 2 3 #仮想トークン属性 4 attr_accessor :remember_token, :activation_token, :reset_token 5 6 before_save :downcase_email 7 before_create :create_activation_digest 8 9 # バリデーション(正規化も含む) 10 validates :name, presence: true, 11 length: { maximum: 50 } 12 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(.[a-z\d\-]+)*.[a-z]+\z/i 13 validates :email, presence: true, 14 length: { maximum: 255 }, 15 format: { with: VALID_EMAIL_REGEX }, 16 uniqueness: { case_sensitive: false } 17 18 #安全なパスワードの生成と、仮想パスワード属性の作成。 19 has_secure_password 20 validates :password, presence: true, 21 length: { minimum: 6 }, 22 allow_nil: true 23 24 # 渡された文字列をハッシュして値を返す 25 def self.digest(string) 26 cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : 27 BCrypt::Engine.cost 28 BCrypt::Password.create(string, cost: cost) 29 end 30 31 # ランダムなトークンを返す。cookiesに使用。 32 def self.new_token 33 SecureRandom.urlsafe_base64 34 end 35 36 # 永続セッションのためにユーザーをデータベースに記憶 37 def remember 38 self.remember_token = User.new_token 39 update_attribute(:remember_digest, User.digest(remember_token)) 40 end 41 42 # 渡されたトークンがダイジェストと一致したらtrue 43 def authenticated?(attribute, token) 44 digest = send("#{attribute}_digest") 45 return false if digest.nil? 46 BCrypt::Password.new(digest).is_password?(token) 47 end 48 49 # 永続セッションを破棄。ログアウト時 50 def forget 51 update_attribute(:remember_digest, nil) 52 end 53 54 # アカウントを有効化 55 def activate 56 update_columns(activated: true, activated_at: Time.zone.now) 57 end 58 59 # 有効化用のメールを送信 60 def send_activation_email 61 UserMailer.account_activation(self).deliver_now 62 end 63 64 # パスワード再設定の属性を設定 65 def create_reset_digest 66 self.reset_token = User.new_token 67 update_columns( reset_digest: User.digest(reset_digest), 68 reset_sent_at: Time.zone.now) 69 end 70 71 # パスワード再設定のメールを送信 72 def send_password_reset_email 73 UserMailer.password_reset(self).deliver_now 74 end 75 76 # パスワード再設定の有効期限が切れている場合はtrue 77 def password_reset_expired? 78 reset_sent_at < 2.hours.ago 79 end 80 81 private 82 83 # emailを全て小文字化 84 def downcase_email 85 self.email.downcase! 86 end 87 88 # 有効化トークンとダイジェストを作成及び代入 89 def create_activation_digest 90 self.activation_token = User.new_token 91 self.activation_digest = User.digest(activation_token) 92 end 93end 94

####パスワードリセットのテスト

Ruby

1require 'test_helper' 2 3class PasswordResetsTest < ActionDispatch::IntegrationTest 4 5 def setup 6 ActionMailer::Base.deliveries.clear 7 @user = users(:michael) 8 end 9 10 test "password resets" do 11 get new_password_reset_path 12 assert_template 'password_resets/new' 13 # メールアドレスが無効 14 post password_resets_path, params: { password_reset: { email: "" } } 15 assert_not flash.empty? 16 assert_template 'password_resets/new' 17 # メールアドレスが有効 18 post password_resets_path, 19 params: { password_reset: { email: @user.email } } 20 assert_not_equal @user.reset_digest, @user.reload.reset_digest 21 assert_equal 1, ActionMailer::Base.deliveries.size 22 assert_not flash.empty? 23 assert_redirected_to root_url 24 25 # 以下、パスワード再設定フォームのテスト 26 user = assigns(:user) 27 # メールアドレスが無効 28 get edit_password_reset_path(user.reset_token, email: "") 29 assert_redirected_to root_url 30 # 無効なユーザー 31 user.toggle!(:activated) 32 get edit_password_reset_path(user.reset_token, email: user.email) 33 assert_redirected_to root_url 34 user.toggle!(:activated) 35 # メールアドレスが有効で、トークンが無効 36 get edit_password_reset_path('wrong token', email: user.email) 37 assert_redirected_to root_url 38 # メールアドレスもトークンも有効 39 get edit_password_reset_path(user.reset_token, email: user.email) 40 assert_template 'password_resets/edit' 41 assert_select "input[name=email][type=hidden][value=?]", user.email 42 # 無効なパスワードとパスワード確認 43 patch password_reset_path(user.reset_token), 44 params: { email: user.email, 45 user: { password: "foobaz", 46 password_confirmation: "barquux" } } 47 assert_select 'div#error_explanation' 48 # パスワードが空 49 patch password_reset_path(user.reset_token), 50 params: { email: user.email, 51 user: { password: "", 52 password_confirmation: "" } } 53 assert_select 'div#error_explanation' 54 # 有効なパスワードとパスワード確認 55 patch password_reset_path(user.reset_token), 56 params: { email: user.email, 57 user: { password: "foobaz", 58 password_confirmation: "foobaz" } } 59 assert is_logged_in? 60 assert_not flash.empty? 61 assert_redirected_to user 62 end 63end 64 65

試したこと

####チュートリアルのコードをコピー&ペースト

####teratailの他記事を実践

https://teratail.com/questions/227521

https://teratail.com/questions/201651?link=qa_related_pc

https://teratail.com/questions/239085
(未解決の同症状記事)


色々試していく中で、valid_user (password_resets_controller の beforeフィルタ)が悪さしているのではないかというところまでは分かったのですが、どう解決したらいいのかが分からずに詰まっております。

ご助言いただければとても嬉しいです。
よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

自己解決

Userモデルの以下の部分が間違って入力していました

###誤り

# パスワード再設定の属性を設定 def create_reset_digest self.reset_token = User.new_token update_columns( reset_digest: User.digest(reset_digest), reset_sent_at: Time.zone.now) end

###正

# パスワード再設定の属性を設定 def create_reset_digest self.reset_token = User.new_token update_columns( reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now) end

コピー&ペーストに漏れがあっただけでした

投稿2020/02/09 09:41

K2_Yoshiko

総合スコア4

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問