前提・実現したいこと
Ruby on Railsでオリジナルアプリを作成中です。
Railsチュートリアルに倣ってUserモデルを作成し、
Everyday Railsを拾い読みしながらRspecでテストを書いていますが
テストが通らず詰まっています。
解決したいこと/発生している問題・エラーメッセージ
具体的には、メール認証を使ったユーザー登録のテストをシステムスペックで書いていますが、
下記内容でテストが失敗しています。
Failures: 1) Users User CRUD creating a new user creates a new user Failure/Error: visit edit_user_account_activation_path(@user.activation_token, email: @user.email) ActionController::UrlGenerationError: No route matches {:action=>"edit", :controller=>"user_account_activations", :email=>"test@example.com", :id=>nil}, possible unmatched constraints: [:id] Did you mean? edit_user_account_activation_url
possible unmatched constraints: [:id]
とありこれが原因だと考えていますが、
ここがなぜnilになってしまうのかがわかりません。
ブラウザで手動で動かしてみると期待通りの動きをしているので、
ルーティングや他のコードが間違っているわけではなさそうだと考えており、
テストの理解が不足していてその書き方が誤っているのだと思うのですが、
原因と修正すべき点や確認すべき事項などアドバイスいただけますと幸いです。
該当のソースコード
spec/system/users_spec.rb
RSpec
1require 'rails_helper' 2 3RSpec.describe 'Users', js: true, type: :system do 4 describe 'User CRUD' do 5 let(:user) { FactoryBot.build(:user) } 6 let(:user_not_activated) { FactoryBot.build(:user, activated: false) } 7 let(:another_user) { FactoryBot.create(:user, email: 'another@example.com') } 8 before do 9 @number_of_users = User.count 10 ActionMailer::Base.deliveries.clear 11 end 12 13 context 'creating a new user' do 14 it 'creates a new user' do 15 visit signup_path 16 fill_in '名前', with: user_not_activated.name 17 fill_in 'メールアドレス', with: user_not_activated.email 18 fill_in 'パスワード', with: user_not_activated.password 19 fill_in 'パスワード(確認)', with: user_not_activated.password_confirmation 20 click_button 'ユーザー登録' 21 22 expect(ActionMailer::Base.deliveries.size).to eq 1 23 24 @user = User.find_by(email: user_not_activated.email) 25 expect(@user).to_not be_activated 26 27 visit edit_user_account_activation_path(@user.activation_token, email: @user.email) 28 @user.reload 29 expect(@user).to be_activated 30 expect(get_me_the_cookie('remember_token')).to_not eq nil 31 expect(page).to have_current_path edit_user_url(@user) 32 expect(page).to have_content 'ようこそ!' 33 34 expect(User.count).to eq @number_of_users + 1 35 end 36 37#以下略
app/models/user.rb
RubyonRails
1class User < ApplicationRecord 2 attr_accessor :remember_token, :activation_token 3 4 before_save :downcase_email 5 before_create :create_activation_digest 6 validates :name, presence: true, length: { maximum: 50 } 7 8 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+.[a-z]+\z/i 9 validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: true 10 11 VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)\w{8,12}\z/ 12 has_secure_password 13 validates :password, presence: true, 14 format: { with: VALID_PASSWORD_REGEX, message: 'は半角8~12文字で英大文字・小文字・数字それぞれ1文字以上含む必要があります' }, 15 allow_nil: true 16 17 # 渡された文字列のハッシュ値を返す 18 def self.digest(string) 19 cost = if ActiveModel::SecurePassword.min_cost 20 BCrypt::Engine::MIN_COST 21 else 22 BCrypt::Engine.cost 23 end 24 BCrypt::Password.create(string, cost: cost) 25 end 26 27 # ランダムなトークンを返す 28 def self.new_token 29 SecureRandom.urlsafe_base64 30 end 31 32 # 永続セッションのためにユーザーをデータベースに記憶する 33 def remember 34 self.remember_token = User.new_token 35 update_attribute(:remember_digest, User.digest(remember_token)) 36 end 37 38 # 渡されたトークンがダイジェストと一致したらtrueを返す 39 def authenticated?(attribute, token) 40 digest = send("#{attribute}_digest") 41 return false if digest.nil? 42 43 BCrypt::Password.new(digest).is_password?(token) 44 end 45 46 def forget 47 update_attribute(:remember_digest, nil) 48 end 49 50 private 51 52 def downcase_email 53 email.downcase! 54 end 55 56 def create_activation_digest 57 self.activation_token = User.new_token 58 self.activation_digest = User.digest(activation_token) 59 end 60end 61
app/controllers/users_controller.rb
RubyonRails
1class UsersController < ApplicationController 2 before_action :logged_in_user, only: %i[show edit update destroy] 3 before_action :correct_user, only: %i[edit update destroy] 4 def new 5 @user = User.new 6 return unless logged_in? 7 8 redirect_to root_url 9 end 10 11 def create 12 @user = User.new(user_params) 13 if @user.save 14 UserMailer.account_activation(@user).deliver_now 15 flash[:info] = 'アカウント認証メールを確認して登録を完了してください' 16 redirect_to root_url 17 else 18 render 'new' 19 end 20 end 21 22#以下略
app/controllers/user_account_activations_controller.rb
RubyonRails
1class UserAccountActivationsController < ApplicationController 2 def edit 3 user = User.find_by(email: params[:email]) 4 if user && !user.activated? && user.authenticated?(:activation, params[:id]) 5 user.update_attribute(:activated, true) 6 user.update_attribute(:activated_at, Time.zone.now) 7 log_in user 8 flash[:success] = 'ようこそ!' 9 redirect_to edit_user_url user 10 else 11 flash[:danger] = 'このURLは無効です' 12 redirect_to root_url 13 end 14 end 15end
試したこと
pメソッドで@user
の中身を確認しました。
spec/system/users_spec.rb
RSpec
1#これより前省略 2 context 'creating a new user' do 3 it 'creates a new user' do 4 visit signup_path 5 fill_in '名前', with: user_not_activated.name 6 fill_in 'メールアドレス', with: user_not_activated.email 7 fill_in 'パスワード', with: user_not_activated.password 8 fill_in 'パスワード(確認)', with: user_not_activated.password_confirmation 9 click_button 'ユーザー登録' 10 11 @user = User.find_by(email: user_not_activated.email) 12 expect(ActionMailer::Base.deliveries.size).to eq 1 13 expect(@user).to_not be_activated 14 15 p @user.activation_token # <---- デバッグ用に追記 16 p @user # <---- デバッグ用に追記 17 visit edit_user_account_activation_path(@user.activation_token, email: @user.email) 18#これより後省略
その結果、(エラーメッセージにも出ていた通りですが)
@user.activation_token
の中身がnil
となっており、これが原因だと考えているのですが
なぜnil
になってしまうのかがわかりません。
@user.activation_token
から生成される@user.activation_digest
には値が入っていました。
ということは一度は生成されたactivation_tokenの値が消えてしまっている?のでしょうか。
補足情報(FW/ツールのバージョンなど)
環境:ローカル環境
version | |
---|---|
macOS Big Sur | 11.2.3 |
Ruby | 3.0.0 |
Rails | 6.1.3 |
Rspec | 3.10 |
(rspec-rails) | 5.0.1 |
capybara | 3.26 |
その他、情報の過不足などございましたらご教示ください。
よろしくお願いいたします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。