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

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

ただいまの
回答率

90.51%

rails tutorial12章で、editからのpassword_resetの検証に失敗してrenderした時のurlが不適切

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 26

shumbow

score 8

発生している問題

タイトルの通りなのですがrails tutorial 12章 ここのあたりです で、password再設定を実装しているのですが、formで不正な値を入れてpatch password_reset_path(reset_token)をすると、バリデーションでひっかかってeditをrenderするというありがちなやつだと思うんですけど、通常のeditへのurlは(password再設定メールから飛んできたリンク)、http://http://localhost:3000/password_resets/Wg5lJNFsK84NeWVNcdIovQ/edit/?email=xxx%40yyyyyy
(:idは@user.reset_token)にがなるのですがrenderで表示されたeditのurlは
http://http://localhost:3000/password_resets/Wg5lJNFsK84NeWVNcdIovQ
と、edit以下が消えてしまっています。そのため、この状態でブラウザを更新するとno routes match エラーが発生します。

No route matches [GET] "/password_resets/Wg5lJNFsK84NeWVNcdIovQ"

root_path    GET    /    
main_pages#top

help_path    GET    /help(.:format)    
main_pages#help

signup_path    GET    /signup(.:format)    
users#new

POST    /signup(.:format)    
users#create

login_path    GET    /login(.:format)    
sessions#new

POST    /login(.:format)    
sessions#create

logout_path    DELETE    /logout(.:format)    
sessions#destroy

users_path    GET    /users(.:format)    
users#index

POST    /users(.:format)    
users#create

new_user_path    GET    /users/new(.:format)    
users#new

edit_user_path    GET    /users/:id/edit(.:format)    
users#edit

user_path    GET    /users/:id(.:format)    
users#show

PATCH    /users/:id(.:format)    
users#update

PUT    /users/:id(.:format)    
users#update

DELETE    /users/:id(.:format)    
users#destroy

edit_account_activation_path    GET    /account_activations/:id/edit(.:format)    
account_activations#edit

password_resets_path    POST    /password_resets(.:format)    
password_resets#create

new_password_reset_path    GET    /password_resets/new(.:format)    
password_resets#new

edit_password_reset_path    GET    /password_resets/:id/edit(.:format)    
password_resets#edit

password_reset_path    PATCH    /password_resets/:id(.:format)    
password_resets#update

PUT    /password_resets/:id(.:format)    
password_resets#update


考えられる原因としては、railstutorialはたぶんraisl5.1.2なのにたいして自分は5.1.7なのでそれか、form作成にform_forではなくform_withを使っているからなのかもしれませが、そもそもtutorialの方でも起きているバグなのかもわかりません。(git cloneして調べようとしたが、bundlerのバージョンの関係でbundle install失敗しました)
実際はユーザーが戻るボタンで戻れば問題なく使えるのでなおさなくてもよいかもしれないので、この程度のエラーは放置するべきなのでしょうか?でも解決方法がわかる方はぜひ教えていただきたいです。

試したこと、惜しかったところ

renderじゃなくてredirect_to(password_reset_path(params[:id], @user.email))
として明示的にフルパスを示せばいいじゃないかとおもってやってみたらうまく機能したのですが、バリデーション失敗のエラーメッセージが消えてしまうので、結局使っていません。(また、余計なリクエストも増えてしまうといやなので)
以下関係するファイルです。

views/password_resets/edit.html.erb

<% provide(:title, 'パスワード再設定') %>
<h1 class="heading">パスワード再設定</h1>
<p>新しいパスワードを設定してください</p>
    <%= form_with(model: @user, url: password_reset_path(params[:id]), local: true) do |form| %>
    <div class="row">
      <div class="col-10 offset-md-1">
        <%= render 'shared/error_messages'%>
      </div>
    </div>

    <div class="row">
      <div class="col-10 col-md-8 mx-auto">
        <%= hidden_field_tag :email, @user.email %>
        <%= form.label :password, "パスワード" %><small class="text-muted">  半角英数字で6以上20文字以下で設定</small>
        <%= form.password_field :password, class: 'form-control' %>
      </div>
    </div>
    <div class="row">
      <div class="col-10 col-md-8 mx-auto">
        <%= form.label :password_confirmation, "パスワード確認" %><small class="text-muted"> 確認のためもう一度ご入力ください</small>
        <%= form.password_field  :password_confirmation, class: 'form-control' %>
      </div>
    </div>
    <div class="row mt-3">
      <div class="col-3 mx-auto">
        <%= form.submit "更新する", class: "btn btn-primary submit" %>
      </div>
    </div >
    <% end %>
</div>


controller/password_resets_controller.rb

class PasswordResetsController < ApplicationController
  before_action :get_user,   only: [:edit, :update]
  before_action :valid_user, only: [:edit, :update]
  before_action :check_expiration, only: [:edit, :update]

  def new
  end

  def create
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
      @user.create_reset_digest
      @user.send_password_reset_email
      flash[:success] = "再設定用リンクを送りました。ご確認ください。"
      redirect_to root_url
    else
      flash[:danger] = "このメールアドレスは登録されていません"
      render 'new'
    end
  end

  def edit
  end

  def update
    if params[:user][:password].empty?
      @user.errors.add(:password, :blank)
      render 'edit'
    elsif @user.update_attributes(user_params)
      log_in @user
      @user.update_attribute(:reset_digest, nil)
      flash[:success] = "パスワード変更されました"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

   def user_params
     params.require(:user).permit(:password, :password_confirmation)
   end

   def get_user
     @user = User.find_by(email: params[:email])
   end

   # 正しいユーザーかどうか確認する
   def valid_user
     unless (@user && @user.activated? &&
             @user.authenticated?(:reset, params[:id]))
       redirect_to root_url
     end
   end

   def check_expiration
     if @user.password_reset_expired?
       flash[:danger] = "有効期限(2時間)が切れています。もう一度やり直してください。"
       redirect_to new_password_reset_url
     end
   end
end
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

同じタグがついた質問を見る