LoginSignup
2
1

More than 5 years have passed since last update.

どこにも答えがない。Rails 5.1 第4版 11.3.3 演習3でつまずく

Posted at

自分と同じように、Rails 5.1 第4版 11.3.3 演習3でつまずいた人のお役に立てるといいなと思いまとめました。

答えをまとめているサイトを3つくらい見たのですが、演習3だけは、答えを書いていないか、回答どおりにすると、別の箇所でエラーが起きます。(自分が探しきれていないだけかもしれません)

なので、自分でエラーを修正しました。

演習1は影響ないので飛ばします。

演習2

現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.40のテンプレートを使って、この動作を変更してみましょう9。なお、ここで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。

これに対して、リスト11.40はこのようになっています。

リスト 11.40: 有効なユーザーだけを表示するコードのテンプレート
app/controllers/users_controller.rb

class UsersController < ApplicationController
  .
  .
  .
  def index
    @users = User.where(activated: FILL_IN).paginate(page: params[:page])
  end

  def show
    @user = User.find(params[:id])
    redirect_to root_url and return unless FILL_IN
  end
  .
  .
  .
end

この演習は、indexアクションにwhereメソッドを追加したことにより、activated: trueのユーザーが表示されるようになります。
また、showアクションについてはactivated?メソッドによって、アクティベート済みのユーザでなければ、root_urlにリダイレクトします。

なので、FILL_INの箇所が、以下のようになります。

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
  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 show
    @user = User.find(params[:id])
    redirect_to root_url and return unless @user.activated?
  end

この変更をしたことにより、アクティベートされていないユーザーは、indexページにひょうじされなくなりました。

次は演習3です

ここまでの演習課題で変更したコードをテストするために、/users と /users/:id の両方に対する統合テストを作成してみましょう。

とあるので演習2に対するテストを作成します。

有効化されていないユーザーを作成しないことには、indexアクション、showアクションで表示されていないかを調べられないので、fixtures/users.ymlのユーザーをひとり、有効化されていないことにします。

fixtures/users.yml

.
.
.
lana:
  name: Lana Kane
  email: hands@example.gov
  password_digest: <%= User.digest('password') %>
  activated: false
  activated_at: <%= Time.zone.now %>

activated: falseにしました。

このユーザーをsetupメソッドに追加します。

require 'test_helper'

class UsersIndexTest < ActionDispatch::IntegrationTest

  def setup
    @admin         = users(:michael)
    @non_admin     = users(:archer)
    @non_activated = users(:lana)
  end

あとは、テストを追加します。

app/controllers/users_controller.rb

  test "not allow the not activated user" do
#アクティベートされていないユーザーを許可しない
    log_in_as(@non_activated)
#アクティベートしていないユーザーでログイン
    assert_not @non_activated.activated?
#アクティベートされていなければ、GREEN
    get users_path
#getリクエストを送る(ユーザー一覧ページ)
    assert_select "a[href=?]", user_path(@non_activated), count: 0
#ユーザー一覧ページのなかに、アクティベートされていないユーザのリンクがなければGREEN
    get user_path(@non_activated)
#getリクエストを送る(アクティベートされていないユーザーのprofileページを表示)
    assert_redirected_to root_url
#root_urlへリダイレクトしたらテストはGREEN
  end

これで、このテスト(test "not allow the not activated user" do end)はGREENなのですが、

test/integration/users_index_test.rb

  test "index as admin including pagination and delete links" do
    log_in_as(@admin)
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
    first_page_of_users = User.paginate(page: 1)
    first_page_of_users.each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
      unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end
    end
    assert_difference 'User.count', -1 do
      delete user_path(@non_admin)
    end
  end

もとからあった、このテストがREDになります。
テストの結果このあたりの行でエラーがあると表示されたので、テストないようの、この部分を見ていきます。

    first_page_of_users = User.paginate(page: 1)
    first_page_of_users.each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
      unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end
    end

first_page_of_user.each do |user|
でuser変数には、1ページ目のユーザーが代入されます。
そのユーザーの数だけ、
assert_select 'a[href=?]', user_path(user), text: user.name
でuser_pathをチェックするのですが、演習2をおこなったことにより、アクティベートされたユーザーが(activated: true)表示されています。なので、アクティベートされていないユーザーは表示されていません。

演習2の下記の箇所です。

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

なので、アクティベートされていないユーザーのuser_pathがユーザー一覧のページに(users_path)表示されていないので、REDになります。

これを解決するために、アクティベートされていないユーザーは、このテストを回避することにします。それはそれで問題がおこりそうですが、

すでに、演習3で追加したテスト
test "not allow the not activated user"
の中で

    assert_select "a[href=?]", user_path(@non_activated), count: 0

このように、アクティベートされていないユーザーのリンク(user_path)は表示されていない(count: 0)ことがわかっているので大丈夫だと判断します。

ということで、テスト内容を変更します。

    first_page_of_users = User.paginate(page: 1)
    first_page_of_users.each do |user|
      unless user == @non_activated
        assert_select 'a[href=?]', user_path(user), text: user.name
      end
      unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end
    end

追加した内容は、以下です。

unless == @non_activated

end

この内容を追加したことによりアクティベートされていないユーザーは、

assert_select 'a[href=?]', user_path(user), text: user.name

このテストを回避しました。

これでも、まだえらーがでるので、次は

unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end

この部分です。この時点で
admin属性がtrueのユーザーは、ユーザーを削除するリンクが表示されません。また、削除用のリンクである、deleteというテキストも表示されません。
なので、admin属性がtrueのユーザーは

assert_select 'a[href=?]', user_path(user), text: 'delete'

このテストを通過しないようにしています。
これと同様に、アクティベートされていないユーザーも削除用のリンクが表示されませんし、deleteというテキストも表示されません。(そもそも、アクティベートされていないユーザーは、ユーザー一覧に表示されていません)
なので、アクティベートされていないユーザーもこのテストを通過しないようにします。

unless user == @admin || @non_activated
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end

このように、|| @non_activatedとすることにより、
@adminか、@non_activatedはこのテストを通過しないことになりました。
ここでテストはGREENになります。

ためしに、演習2の内容を元にもどして、テストがREDになることを確認しました。

Expected response to be a <3XX: redirect>, but was a <200: OK>

テスト結果はリダイレクトのレスポンスがくるはずが、リダイレクトでなく、成功を示しているのでテストはREDです。

もう一度演習2の内容を直して。テストをすると、テストはGREENになります。

この演習内容だけは、自分で探した範囲では、詳細が書いていなかったので、まとめてみました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1