第8章Railsチュートリアル演習問題と解答まとめ

Ruby on Railsチュートリアルの演習問題と解答をまとめる。


第8章 基本的なログイン機構 - Railsチュートリアル

f:id:yukitoku_sw:20191019165508p:plain

アウトプットすることで、より自分の理解を深めることを目的としています。 自分なりに調べて考えた回答のため、記載内容に誤りがある場合はコメントいただけると幸いです。


演習8.1.1 Sessionコントローラ

問題1

GET login_pathとPOST login_pathとの違いを説明できますか? 少し考えてみましょう。

解答

Getは何かを取得するアクション。つまりsessions/new.html.erbを受け取って表示する。
POSTは変更を加えるアクション。つまりlogin状態を作る(create)する。


問題2

ターミナルのパイプ機能を使ってrails routesの実行結果とgrepコマンドを繋ぐことで、Usersリソースに関するルーティングだけを表示させることができます。同様にして、Sessionsリソースに関する結果だけを表示させてみましょう。現在、いくつのSessionsリソースがあるでしょうか? ヒント: パイプやgrepの使い方が分からない場合は Learn Enough Command Line to Be Dangerousの Section on Grep (英語) を参考にしてみてください。

解答

$ rails routes | grep users
   signup GET    /signup(.:format)         users#new
          POST   /signup(.:format)         users#create
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PATCH  /users/:id(.:format)      users#update
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy

$ rails routes | grep sessions
    login GET    /login(.:format)          sessions#new
          POST   /login(.:format)          sessions#create
   logout DELETE /logout(.:format)         sessions#destroy

sessionsのリソースは3つ!


演習8.1.2 ログインフォーム

問題1

リスト 8.4で定義したフォームで送信すると、Sessionsコントローラのcreateアクションに到達します。Railsはこれをどうやって実現しているでしょうか? 考えてみてください。ヒント:表 8.1とリスト 8.5の1行目に注目してください。

解答

form_forはmethodにて、POSTを生成するように設定されている。
引数に(:session, url: login_path)が設定されているので、
sessionコントローラ内でurlがlogin_pathのPOSTつまり
sessions#createに到達する


演習8.1.3 ユーザーの検証と認証

問題1

Railsコンソールを使って、表 8.2のそれぞれの式が合っているか確かめてみましょう. まずはuser = nilの場合を、次にuser = User.firstとした場合を確かめてみてください。ヒント: 必ず論理値オブジェクトとなるように、4.2.3で紹介した!!のテクニックを使ってみましょう。例: !!(user && user.authenticate('foobar'))

解答

>> user = nil
=> nil
>> !!(user && user.authenticate('foobar'))
=> false

>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2019-10-22 11:28:1
5", updated_at: "2019-10-22 11:28:15", password_digest: "$2a$10$qJNgcZhLTc4MMK1hAcmuk.QnAXOdwbkcu65k9FCE4Zh.
..">
>> !!(user && user.authenticate('foobar'))
=> false

>> !!(user && user.authenticate('password'))
=> true

ユーザー登録時に自分で登録したパスワードを引数に入れるとtrueになる。

最初焦ります


演習8.1.4 フラッシュメッセージを表示する

問題1

8.1.4の処理の流れが正しく動いているかどうか、ブラウザで確認してみてください。特に、flashがうまく機能しているかどうか、フラッシュメッセージの表示後に違うページに移動することを忘れないでください。

解答

動作確認なので省略


演習8.2.1 log_inメソッド

問題1

有効なユーザーで実際にログインし、ブラウザからcookiesの情報を調べてみてください。このとき、sessionの値はどうなっているでしょうか? ヒント: ブラウザでcookiesを調べる方法が分からない? 今こそググってみるときです! (コラム 1.1)

解答

f:id:yukitoku_sw:20191023202438p:plain


問題2

先ほどの演習課題と同様に、Expiresの値について調べてみてください。

解答

Expiresとは有効期限のことなので、ブラウザセッション終了時。


演習8.2.2 現在のユーザー

問題1

Railsコンソールを使って、User.find_by(id: ...)で対応するユーザーが検索に引っかからなかったとき、nilを返すことを確認してみましょう。

解答

>> User.find_by(id: 1)
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]
]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2019-10-22 11:28:1
5", updated_at: "2019-10-22 11:28:15", password_digest: "$2a$10$qJNgcZhLTc4MMK1hAcmuk.QnAXOdwbkcu65k9FCE4Zh.
..">

>> User.find_by(id: 5)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 5], ["LIMIT", 1]
]
=> nil

まだ2人しかユーザーを登録していないので、idを5(1と2以外)にするとnilが返ってくる。


問題2

先ほどと同様に、今度は:user_idキーを持つsessionハッシュを作成してみましょう。リスト 8.17に記したステップに従って、||=演算子がうまく動くことも確認してみましょう。

解答

>> session = {}
=> {}
>> session[:user_id] = nil
=> nil
>> @current_user ||= User.find_by(id: session[:user_id])
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ?  [["LIMIT", 1]]
=> nil
>> session[:user_id] = User.first.id
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 1
>> @current_user ||= User.find_by(id: session[:user_id])
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]
]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2019-10-22 11:28:1
5", updated_at: "2019-10-22 11:28:15", password_digest: "$2a$10$qJNgcZhLTc4MMK1hAcmuk.QnAXOdwbkcu65k9FCE4Zh.
..">
>> @current_user ||= User.find_by(id: session[:user_id])
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2019-10-22 11:28:1
5", updated_at: "2019-10-22 11:28:15", password_digest: "$2a$10$qJNgcZhLTc4MMK1hAcmuk.QnAXOdwbkcu65k9FCE4Zh.
..">  


演習8.2.3 レイアウトリンクを変更する

問題1

ブラウザのcookieインスペクタ機能を使って (8.2.1.1)、セッション用のcookieを削除してみてください。ヘッダー部分にあるリンクは非ログイン状態のものになっているでしょうか? 確認してみましょう。

解答

cookieを削除し、ブラウザを再読み込みするとヘッダーが非ログイン状態に変わる


問題2

もう一度ログインしてみて、ヘッダーのレイアウトが変わったことを確認してみましょう。その後、ブラウザを再起動させ、再び非ログイン状態に戻ったことも確認してみてください。注意: もしブラウザの [閉じたときの状態に戻す] 機能をオンにしていると、セッション情報も復元される可能性があります。もしその機能をオンにしている場合、忘れずにオフにしておきましょう (コラム 1.1)。

解答

動作確認なので省略


演習8.2.4 レイアウトの変更をテストする

問題1

試しにSessionヘルパーのlogged_in?メソッドから!を削除してみて、リスト 8.23が redになることを確認してみましょう。

解答

 FAIL["test_login_with_valid_information", UsersLoginTest, 0.8078430001623929]
 test_login_with_valid_information#UsersLoginTest (0.81s)
        Expected exactly 0 elements matching "a[href="/login"]", found 1..
        Expected: 0
          Actual: 1

!を外すとREDになる


問題2

先ほど削除した部分 (!) を元に戻して、テストが greenに戻ることを確認してみましょう。

解答

元に戻すとGREENになる


演習8.2.5 ユーザー登録時にログイン

問題1

リスト 8.25のlog_inの行をコメントアウトすると、テストスイートは red になるでしょうか? それとも green になるでしょうか? 確認してみましょう。

解答

 FAIL["test_valid_signup_information", UsersSignupTest, 0.8600169999990612]
 test_valid_signup_information#UsersSignupTest (0.86s)
        Expected false to be truthy.
        test/integration/users_signup_test.rb:31:in `block in <class:UsersSignupTest>'

REDになるう


問題2

現在使っているテキストエディタの機能を使って、リスト 8.25をまとめてコメントアウトできないか調べてみましょう。また、コメントアウトの前後でテストスイートを実行し、コメントアウトすると red に、コメントアウトを元に戻すと green になることを確認してみましょう。ヒント: コメントアウト後にファイルを保存することを忘れないようにしましょう。また、テキストエディタコメントアウト機能については Test Editor Tutorial の Commenting Out (英語) などを参照してみてください。

解答

command + A 全選択
command + / コメントアウト


演習8.3 ログアウト

問題1

ブラウザから [Log out] リンクをクリックし、どんな変化が起こるか確認してみましょう。また、リスト 8.31で定義した3つのステップを実行してみて、うまく動いているかどうか確認してみましょう。

解答

log out クリック
root_url に移動する
ヘッダーがログイン前の状態になる


問題2

cookiesの内容を調べてみて、ログアウト後にはsessionが正常に削除されていることを確認してみましょう。

解答

ログアウト後に確認すると新しいcookieができている。
ログイン時に作成されたものが正常に削除されたかどうかは不明



yukitoku-sw.hatenablog.com