実現したいこと
session_tokenを比較してtrueを返す様にしてテストを通す様にしたい。
発生している問題・分からないこと
railsチュートリアルの10章を進めている最中のテストコードで
ruby
1 test 'successful edit' do 2 log_in_as(@user) 3 get edit_user_path(@user) 4 patch user_path(@user), 5 params: { user: { name: 'Foo Bar', email: 'foo@bar.com', password: 'password',password_confirmation: 'password' } } 6 assert_redirected_to @user 7 @user.reload 8 9 assert_equal 'Foo Bar', @user.name 10 assert_equal 'foo@bar.com', @user.email 11 end 12end
というのがあったのですがassert_redirected_to @userの箇所でshowページが返ってくるのを期待しているのにloginページが返ってきてしまいます。
その原因を自分でbyebugで調査した所途中処理のsession[:session_token] == user.session_tokenの内容が一致していないのが原因だと思いました。
理由としましてはsessions_controller.rbにbyebugを挟んでsession[:session_token]とuser.session_tokenの内容を確認したら内容が食い違っているせいで@current_userが空になっていて下のsession _helper.rbのlogged_in?のcurrent_user.present?がfalseになっておりusers_contoller.rbのeditアクション前で発火するlogged_in_userがfalseになりlogin_urlに返ってしまっていると考えました。
一連のソースコードを書かせて頂きます。(コードブロックの数の制限上ルーティングや一部コードは省かせていただいてます。)
エラーメッセージ
error
1root@34c7bd0bbb60:/app# rails test test/integration/users_edit_test.rb:40 2Running 3 tests in a single process (parallelization threshold is 50) 3Started with run options --seed 52443 4 5 FAIL UsersEditTest#test_successful_edit (0.54s) 6 Expected response to be a redirect to <http://www.example.com/users/762146111> but was a redirect to <http://www.example.com/login>. 7 Expected "http://www.example.com/users/762146111" to be === "http://www.example.com/login". 8 test/integration/users_edit_test.rb:45:in `block in <class:UsersEditTest>' 9 10 3/3: [=============================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00 11 12Finished in 0.54173s 131 tests, 2 assertions, 1 failures, 0 errors, 0 skips
該当のソースコード
user.yml
1michael: 2 name: Michael Example 3 email: michael@example.com 4 password_digest: <%= User.digest('password') %> 5 admin: true 6 7archer: 8 name: Sterling Archer 9 email: duchess@example.gov 10 password_digest: <%= User.digest('password') %> 11 12lana: 13 name: Lana Kane 14 email: hands@example.gov 15 password_digest: <%= User.digest('password') %> 16 17malory: 18 name: Malory Archer 19 email: boss@example.gov 20 password_digest: <%= User.digest('password') %> 21 22<% 30.times do |n| %> 23user_<%= n %>: 24 name: <%= "User #{n}" %> 25 email: <%= "user-#{n}@example.com" %> 26 password_digest: <%= User.digest('password') %> 27<% end %>
users_edit_test.rb
1def setup 2 @user = users(:michael) 3end 4 5test 'successful edit' do 6 log_in_as(@user) 7 get edit_user_path(@user) 8 patch user_path(@user), 9 params: { user: { name: 'Foo Bar', email: 'foo@bar.com', password: 'password',password_confirmation: 'password' } } 10 assert_redirected_to @user 11 @user.reload 12 13 assert_equal 'Foo Bar', @user.name 14 assert_equal 'foo@bar.com', @user.email 15 end
test_helper.rb
1module ActionDispatch 2 class IntegrationTest 3 4 def log_in_as(user, password: 'password', remember_me: '1') 5 post login_path, params: { session: { email: user.email, 6 password: password, 7 remember_me: remember_me } } 8 end 9 end 10end
sessions_controller.rb
1def create 2 user = find_user_by_email 3 if authenticated?(user) 4 perform_login(user) 5 else 6 handle_failed_authentication 7 end 8 end 9 10 private 11 12def find_user_by_email 13 User.find_by(email: params[:session][:email].downcase) 14end 15 16def authenticated?(user) 17 user&.authenticate(params[:session][:password]) 18end 19 20def perform_login(user) 21 forwarding_url = session[:forwarding_url] 22 reset_session 23 manage_remember_me(user) 24 log_in user 25 redirect_to forwarding_url || user 26end 27 28def manage_remember_me(user) 29 params[:session][:remember_me] == '1' ? remember(user) : forget(user) 30end 31 32def log_in(user) 33 session[:user_id] = user.id 34#ここで一回目のuser.session_tokenが入る 35 session[:session_token] = user.session_token 36 end 37 38def current_user 39 if (user_id = session[:user_id]) 40 user = User.find_by(id: user_id) 41 @current_user = user if user && session[:session_token] == user.session_token 42 #ここにbyebugを挟んでsession[:session_token]とuser.session_tokenの内容を確認したら内容が食い違っている。 43 そのせいで@current_userが空になっていて下のsession _helper.rbのlogged_in?のcurrent_user.present?がfalseになっておりusers_contoller.rbのeditアクション前で発火するlogged_in_userがfalseになりlogin_urlに返ってしまっている。 44 elsif (user_id = cookies.encrypted[:user_id]) 45 user = User.find_by(id: user_id) 46 if user&.authenticated?(cookies[:remember_token]) 47 log_in user 48 @current_user = user 49 end 50 end 51 end 52 53 def current_user?(user) 54 user && user == current_user 55 end
users_controller.rb
1before_action :logged_in_user, only: %i[index edit update destroy] 2before_action :correct_user, only: %i[edit update] 3 4def edit 5 @user = User.find(params[:id]) 6end 7 8def update 9 if @user.update(user_params) 10 flash[:success] = 'Profile updated' 11 redirect_to @user 12 else 13 render 'edit', status: :unprocessable_entity 14 end 15 end 16 17def logged_in_user 18 #ここでfalseが返ってしまいログインでコケてしまい編集ページに飛べずテストが失敗している。 19 return if logged_in? 20 store_location 21 flash[:danger] = 'Please log in.' 22 redirect_to login_url, status: :see_other 23 end 24 25 def correct_user 26 @user = User.find(params[:id]) 27 redirect_to(root_url, status: :see_other) unless current_user?(@user) 28 end 29 30(session _helper.rb) 31def logged_in? 32 current_user.present? 33end
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
・config/initializers/session_store.rb ファイルにて、セッションのキー、有効期限、セキュリティ設定などをしているらしいのでここで極端に有効期限が短くなっているのかと思ったがそもそも対象のファイルがなかった。
・config/environments/development.rb、config/environments/production.rbに記述されている可能性があるらしいがそれらしい記述もなかった。
補足
特になし
あなたの回答
tips
プレビュー