2

私は 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() 呼び出しと何か関係があるのだろうか。

  1. 誰かが私の調査結果を検証または反論できますか?
  2. このテストを正しく書くにはどうすればよいですか?

見つかった解決策

さらに調査したところ、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
4

2 に答える 2

1

「禁止属性」テストが「編集」テスト ブロック内にネストされている場合、同じ動作が見られることを確認したかっただけです。

第 9 章で述べたように、visit を使用するのではなく、直接 POST、PATCH、GET、または DELETE リクエストを行う場合は常に、no_capybara: true オプションを sign_in メソッドに指定して、ユーザーがサインインしています。

ただし、この場合、 no_capybara: true オプションを sign_in とともに使用すると、「編集」ブロックの他のテストは、いくつかのカピバラの問題により失敗します。

OPで述べたように、オプションが省略されている場合、Usersコントローラー内のuser_paramsメソッドの:adminの有無に関係なく、「禁止された属性」テストに合格します。

于 2013-08-25T02:11:35.723 に答える
0

ここでも同じ問題。metafour の助けを借りて、次の作品を見つけました。パッチを機能させるには、capybara: true でユーザーをサインインする必要があります。

describe "forbidden attributes" do
  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
于 2013-08-28T00:16:39.613 に答える