私は Michael Hartl の Rails チュートリアルの Rails 4 バージョンに取り組んでいますが、セクション 9.6 の演習 1 で問題が発生しています (リスト 9.49)。
間違った理由でチュートリアルのテストに合格したようです。PATCH リクエストの前に、user.admin? デフォルトでは false です。PATCH リクエスト後 user.admin? PATCH リクエストが UsersController#update メソッドに到達していないため、まだ false です (したがって、テストに合格しています)。
これが私のコードです:
spec/requests/user_pages_spec.rb (other tests removed to isolate the one in question):
require 'spec_helper'
describe "User pages" do
subject { page }
describe 'edit' do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
describe "forbidden attributes" do
let(:params) do
{ user: { name: 'Forbidden Attributes',
password: user.password,
password_confirmation: user.password,
admin: true } }
end
before { patch user_path(user), params }
specify { expect(user.reload).not_to be_admin }
end
end
end
Relevant parts of app/controllers/users_controller.rb:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update]
before_action :correct_user, only: [:edit, :update]
# PATCH /users/:id
def update
# @user is set in before_action
if @user.update_attributes(user_params)
# handle a successful update
flash[:success] = 'Profile updated'
sign_in @user
redirect_to @user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, **:admin**)
end
# Before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: 'Please sign in.'
end
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
spec/factories.rb:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}@example.com" }
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
end
そして、これがテストログが示すことです:
Started PATCH "/users/2111" for 127.0.0.1 at 2013-08-18 21:30:44 -0400
Processing by UsersController#update as HTML
Parameters: {"user"=>{"name"=>"Forbidden Attributes", "password"=>"[FILTERED]", \
"password_confirmation"=>"[FILTERED]", "admin"=>"true"}, "id"=>"2111"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = \
'da39a3ee5e6b4b0d3255bfef95601890afd80709' LIMIT 1
**Redirected to http://www.example.com/signin
Filter chain halted as :signed_in_user rendered or redirected**
Completed 302 Found in 2ms (ActiveRecord: 0.4ms)
https://github.com/railstutorial/sample_app_rails_4から参照バージョンのコードをダウンロードして実行しましrspec spec/requests/user_pages_spec.rb
た。テスト ログは同じことを示しました: PATCH 要求は signed_in_user によって停止されており、更新メソッドに到達していません。
admin IS が設定されていることをテストしていくつかの puts ステートメントを追加したところ、サインインしているユーザーがテストされているユーザーと同じではないように見えました。user.id は一定のままですが、user.name は変更されます。工場での sequence() 呼び出しと何か関係があるのだろうか。
- 誰かが私の調査結果を検証または反論できますか?
- このテストを正しく書くにはどうすればよいですか?
見つかった解決策
さらに調査したところ、remember_token が関係しているように見えました。「禁止された属性」テストを「編集」ブロックの外に移動し、「capybara: true」を sign_in 呼び出しに追加すると、機能します。したがって、リスト 9.49 (spec/requests/user_pages_spec.rb) は次のようになります。
require 'spec_helper'
describe "User pages" do
subject { page }
.
.
.
describe "update forbidden attributes" do
let(:user) { FactoryGirl.create(:user) }
let(:params) do
{ user: { admin: true, password: user.password,
password_confirmation: user.password } }
end
before do
sign_in user, no_capybara: true
patch user_path(user), params
end
specify { expect(user.reload).not_to be_admin }
end
end