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

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

ただいまの
回答率

87.78%

RSpecのredirectテストで404エラーが発生してしまう

受付中

回答 2

投稿 編集

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

score 3

Railsチュートリアル14章でRspecのテストを記述していたのですが、どうも引数を指定したpathへのリダイレクトを期待した際に404errorが発生します。routing errorを解消するにはどこを修正すれば良いでしょうか?
一通りメソッドやbefore_actionの見直しをしてみたのですが、原因が突き止められませんでした。capybaraのスクリーンショットも真っ白な画像しか写らず解決には繋がりませんでした。どうかご教示お願いします。

追記)実際にrails sで立ち上げて、自分で非ログイン状態でのリダイレクトを試した所、下記のログのように正常に作動しましたが、なぜかcapybaraでテストをするとエラーになってしまうようです。

サーバーログ

Started GET "/users/3/followers" for 127.0.0.1 at 2020-09-30 01:08:23 +0900
Processing by UsersController#followers as HTML
  Parameters: {"id"=>"3"}
Redirected to http://localhost:3000/login
Filter chain halted as :logged_in_user rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)


Started GET "/login" for 127.0.0.1 at 2020-09-30 01:08:24 +0900
Processing by SessionsController#new as HTML
  Rendering sessions/new.html.haml within layouts/application
  Rendered sessions/new.html.haml within layouts/application (5.9ms)
  Rendered layouts/_shim.html.haml (1.2ms)
  Rendered layouts/_header.html.haml (4.6ms)
  Rendered layouts/_footer.html.haml (2.4ms)
Completed 200 OK in 50ms (Views: 48.1ms | ActiveRecord: 0.0ms)

エラーメッセージ

3) users access to followers or following when not logged in should redirect following when not logged in
     Failure/Error: expect(response).to redirect_to login_path
       Expected response to be a <3XX: redirect>, but was a <404: Not Found>

     [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_users_access_to_followers_or_following_when_not_logged_in_should_redirect_following_when_not_logged_in_922.png


     # ./spec/system/users_spec.rb:41:in `block (4 levels) in <main>'

  4) users access to followers or following when not logged in should redirect followers when not logged in
     Failure/Error: expect(response).to redirect_to login_path
       Expected response to be a <3XX: redirect>, but was a <404: Not Found>

     [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_users_access_to_followers_or_following_when_not_logged_in_should_redirect_followers_when_not_logged_in_669.png


     # ./spec/system/users_spec.rb:45:in `block (4 levels) in <main>'

users_spec.rb

require "rails_helper"

RSpec.describe "create users", type: :system do

  describe "user create a new account" do
    context "submit valid values" do
      it "add users count" do
        expect {
        visit signup_path
        fill_in "Name", with: "testuser"
        fill_in "Email", with: "testuser@example.com"
        fill_in "Password", with: "password"
        fill_in "Confirmation", with: "password"
        click_button "Create Account"}.to change(User, :count).by(1)
      end
    end

    context "submit invalid values" do
      before do
        visit signup_path
        fill_in "Name", with: ""
        fill_in "Email", with: "testuser@invalid"
        fill_in "Password", with: ""
        fill_in "Confirmation", with: ""
        click_button "Create Account"
      end
      it "gets error messages" do
        expect(page).to have_selector("#error_explanation")
        expect(page).to have_selector(".alert-danger")
      end
    end
  end

  describe "access to followers or following" do
    let!(:user) { create(:user) }
    it "should redirect following when not logged in" do
      get following_user_path(user)
      expect(response).to redirect_to login_path
    end
    it "should redirect followers when not loggeg in" do
      get followers_user_path(user)
      expect(response).to redirect_to login_path
    end
  end
end

users_controller.rb

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :followers, :following]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: [:destroy]

  def index
    @users = User.where(activated: true).paginate(page: params[:page])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render "new"
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end

  def show
    @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
    @micropost = current_user.microposts.build if logged_in?
    redirect_to root_url and return unless @user.activated?
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Your profile updated"
      redirect_to @user
    else
      render "edit"
    end
  end

  def following
    @title = "Following"
    @user  = User.find(params[:id])
    @users = @user.following.paginate(page: params[:page])
    render "show_follow"
  end

  def followers
    @title = "Followers"
    @user  = User.find(params[:id])
    @users = @user.followers.paginate(page: params[:page])
    render "show_follow"
  end

  private

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

    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

end

Application.controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper

  private

    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_path
      end
    end

end

spec/factories/users.rb

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
FactoryBot.define do
  factory :user do
    name { "Example User" }
    sequence(:email) { |n| "user_#{n}@example.com" }
    password { "password" }
    password_confirmation { "password" }
    activated {true}
    activated_at {Time.zone.now}
  end
end

models/user.rb

class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships,
        class_name: "Relationship",
       foreign_key: :follower_id,
         dependent: :destroy
  has_many :passive_relationships,
        class_name: "Relationship",
       foreign_key: :followed_id,
         dependent: :destroy
  has_many :following,
    through: "active_relationships",
     source: "followed"
  has_many :followers,
    through: "passive_relationships",
     source: "follower"

  attr_accessor :remember_token, :activation_token, :reset_token
  before_save   :downcase_email
  before_create :create_activation_digest


  validates :name,  presence: true, length: { maximum:  50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true,
    length: { minimum: 6 }, allow_nil: true


  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

  def User.new_token
    SecureRandom.urlsafe_base64
  end

  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end

  def forget
    update_attribute(:remember_digest, nil)
  end

  def activate
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

  def activate
    update_columns(activated: true, activated_at: Time.zone.now)
  end

  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest,  User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end

  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end

  def feed
    Micropost.where("user_id = ?", id)
  end

  def follow(other_user)
    following << other_user
  end

  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  def following?(other_user)
    following.include?(other_user)
  end


  private

    def downcase_email
      self.email = email.downcase
    end

    def create_activation_digest
      self.activation_token  =  User.new_token
      self.activation_digest =  User.digest(activation_token)
    end
end
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

0

おそらくこの記述でエラーが出ていると思いますが、どんなテストをしようとしてるか説明してもらえますか?
(○○して##すると**になっているかどうかみたいな)

(略)
  describe "access to followers or following" do
    let!(:user) { create(:user) }
    it "should redirect following when not logged in" do
      get following_user_path(user)
      expect(response).to redirect_to login_path
    end
    it "should redirect followers when not loggeg in" do
      get followers_user_path(user)
      expect(response).to redirect_to login_path
    end
  end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/09 13:55

    返答遅くなって申し訳ござませんでした。このテストではあるユーザーのフォロワー一覧にアクセスをする時、loginをしていなければlogin画面にbefore_actionでリダイレクトさせたいのですが、そもそもfollowing_user_path(user)がないことになってしまうのです。

    キャンセル

0

そもそもfollowing_user_path(user)がないことになってしまうのです。

これはletでuserを作ってるのでlogin状態であればアクセスできると思います

おそらく問題なのはexpect以降です

expect(response)というのは、200とか404とかを判定するものなので、やりたいテストになってない気がします。

↓以下のように書くのがやりたいテストではないでしょうか?

expect(current_path).to eq new_user_session_path

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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