89340


## 環境

  * Rails7.0
  * Docker

## 概要

現在『Everyday Rails RspecによるRailsテスト入門』でRspecを学習している者です。

requestspecを使用して「Postを送信し、DBに1件対象のデータが増えることを確認する」というテストを行っているのですが、以下のエラーが出てしまいテストが失敗している状態です。

**エラー**

[code]

    expected Project::ActiveRecord_Associations_CollectionProxy#count to have changed by 1, but was changed by 0
    
[/code]

いくつかデバッグを行い、エラー画面を出したところ `Can't verify CSRF token authenticity`
といったRailsのCSRF対策にひっかかってしまっている状態になっていたため、おそらくこれが原因かと思われます。

[![画像の説明をここに入力](https://i.stack.imgur.com/guSU9.png)](https://i.stack.imgur.com/guSU9.png)

ユーザログイン認証にはDeviseを用いております。  
ユーザー生成と対象のデータ生成（Project）はRsepcのFactoryBotを使用しております。  
また、現在自分が使用しているRailsのバージョンは7.0のため、いまいちCSRF対策を通過させるための方法がよくわからないため、もしご存知の方がいらっしゃいましたらご教示いただけますと幸いです。

## 該当コード

spec/requests/projects_api_spec.rb

[code]

    require 'rails_helper'
    
    RSpec.describe "ProjectsApis", type: :request do
    # こちらのテストは成功している
        it "1件のプロジェクトを生み出すこと" do
          user = FactoryBot.create(:user)
          FactoryBot.create(:project, name: "Sample Project")
          FactoryBot.create(:project, name: "Second Sample Project", owner: user)
    
          get api_projects_path, params: {
            user_email: user.email,
            user_token: user.authentication_token
          }
    
          expect(response).to have_http_status(:success)
          json = JSON.parse(response.body)
          expect(json.length).to eq 1
          project_id = json[0]["id"]
    
          get api_projects_path(project_id), params: {
            user_email: user.email,
            user_token: user.authentication_token
          }
    
          expect(response).to have_http_status(:success)
          json = JSON.parse(response.body)
          expect(json[0]["name"]).to eq "Second Sample Project"
        end
    
        # こちらのテストが失敗している
    　　　　　　　　it "プロジェクトを作成できること" do
          user = FactoryBot.create(:user)
          project_attributes = FactoryBot.attributes_for(:project)
    
          expect {
            post api_projects_path, params: {
              user_email: user.email,
              user_token: user.authentication_token,
              project: project_attributes
            }
          }.to change(user.projects, :count).by(1)
    
          expect(response).to have_http_status(:success)
        end
    end
    
[/code]

app/controllers/application_controller.rb

[code]

    class ApplicationController < ActionController::Base
      before_action :authenticate_user!
    
      protected
    
      def set_project
        @project = Project.find(params[:project_id])
      end
    
      def project_owner?
        unless @project.owner == current_user
          redirect_to root_path, alert: "You don't have access to that project."
        end
      end
    end
    
[/code]

spec/factories/projects.rb

[code]

    FactoryBot.define do
      factory :project do
        sequence(:name) { |n| "Project #{n}" }
        description { "A test project" }
        due_on { 1.week.from_now }
        association :owner
    
        # メモ付きのプロジェクト
        trait :with_notes do
          after(:create) { |project| create_list(:note, 5, project: project) }
        end
    
        # 昨日が締め切りのプロジェクト
        trait :due_yesterday do
          due_on { 1.day.ago }
        end
    
        # 今日が締め切りのプロジェクト
        trait :due_today do
          due_on { Date.current.in_time_zone }
        end
    
        # 明日が締め切りのプロジェクト
        trait :due_tomorrow do
          due_on { 1.day.from_now }
        end
    
        # 無効になっている
        trait :invalid do
          name { nil }
        end
      end
    end
    
[/code]

[code]

    FactoryBot.define do
      factory :user, aliases: [:owner] do
        first_name { "Aaron" }
        last_name { "Sumner" }
        sequence(:email) { |n| "tester#{n}@example.com" }
        password { "dottle-nouveau-pavilion-tights-furze" }
      end
    end
    
[/code]


CC BY-SA 4.0
2022-06-06T23:01:37.057
89261
2022-06-12T02:16:29.530
2022-06-11T18:59:25.260
19110
52962
question
ruby-on-rails rspec
request specでPOSTを送信して対象のデータの数を一つ増やしたいが、Can't verify CSRF token authenticityが出てしまう


Rails 7.0 のデフォルトだと test 環境では
`config.action_controller.allow_forgery_protection` が `false` になっており CSRF
トークンの検証がスキップされています:
<https://github.com/rails/rails/blob/1a22ebc/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt#L33-L34>

もしテスト時に CSRF トークンの検証まで行う必要が無いのであれば、この設定を確認してみてください。

テスト時に CSRF トークンの検証まで行いたい場合は、request spec
では明示的にトークンを与えるようにするのが良さそうです。[`ActionController::RequestForgeryProtection#form_authenticity_token`](https://api.rubyonrails.org/v7.0.3/classes/ActionController/RequestForgeryProtection.html#method-
i-form_authenticity_token) を使ってトークンを自前で生成し、`authenticity_token` という名前の param
として渡してあげると通るはず……です。

* * *

ところで、テストが失敗しているのは CSRF トークンのせいではないかもしれません。テストが失敗しているエラーメッセージはあくまで `count`
が意図通り変化していないよという所であり、POST リクエストが失敗したというエラーではありません。POST
リクエストが失敗しているのであれば変化の検出よりも先にそのエラーが出るはずです。

ということで、おそらく `post api_projects_path` で本当にレコードの新規作成が行われていないのではないでしょうか？
このリクエストを処理するコントローラーの実装を見直してみてください。


CC BY-SA 4.0
2022-06-11T18:58:59.707
89340
2022-06-12T02:16:29.530
2022-06-12T02:16:29.530
19110
19110
89261
answer