【Railsチュートリアル】第8章 演習問題解答

【Railsチュートリアル】第8章 演習問題解答

ログイン機能を実装していきます。
MVCモデルをしっかり意識してないと詰むようになってきます。

目次

8.1.1 Sessionsコントローラ

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

解答

参考サイトを載せておこうと思います。
GETとPOSTの違いについて

GETは何かを取得するとき、POSTはなにかを登録する時に使います。
login_pathを表示したい時はGET,login_pathからデータの登録を行う場合はPOSTですね。

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

解答

sessionsでgrepすればいいですね。

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

8.1.2 ログインフォーム

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

解答

railsdoc見ても分かるのですが、
1:form_forヘルパーはpostメソッドを生成します。
http://railsdoc.com/references/form_for

2:sessionコントローラとlogin_pathを引数に指定しています。

1、2を合わせるとsessionコントローラのcreateアクションがリスト8.4のform_forで指定されていることがわかります。

8.1.3 ユーザーの検索と認証

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

解答

以下のようになります。

$ rails c
Running via Spring preloader in process 9364
Loading development environment (Rails 5.1.4)
irb(main):001:0> user = nil
=> nil
#user = nil,passwordなんでも
irb(main):002:0> !!(user && user.authenticate('foobar'))
=> false
irb(main):003:0> user = User.first
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "kojimanotech", email: "kojimanotech@email.com", created_at: "2018-07-05 13:56:06", updated_at: "2018-07-05 13:56:06", password_digest: "$2a$10$rqZ1irlA2uVbSBFJF0jWrOUPKPqbowfdrWG3hmiKxWt...">
# user = User.first,password正しい
irb(main):004:0> !!(user && user.authenticate('kojima'))
# user = User.first,password誤り
=> true
irb(main):005:0> !!(user && user.authenticate('hogehoge'))
=> false

8.1.5 フラッシュのテスト

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

解答

8.1.4ではログインエラーのflashメッセージが表示されている時に「Home」をクリックして画面移動しても
flashメッセージが残ってしまうというものでした。

同じ手順を踏んでいき、「Home」をクリックしてからflashメッセージが表示されなくなることを確認してください。

8.2.1 log_inメソッド

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

解答

Chromeでcookieを確認する方法
上記サイトを参考にすればできます。

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

解答

chromeから参照するとExpiresでなく、有効期限という表示になってますが同意です。
ブラウザセッションの終了時と表示されているはずです。

8.2.2 現在のユーザー

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

解答

2.にまとめて記載。ここでは省略。

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

解答

リスト8.17に沿ってやればOKです。
以下のようになることを確認してください。

$ rails c
Running via Spring preloader in process 29180
Loading development environment (Rails 5.1.4)
irb(main):001:0> session ={}
=> {}
irb(main):002:0> session[:user_id] = nil
=> nil
irb(main):003:0> # 8.2.2.1
irb(main):004:0* @current_user ||= User.find_by(id: session[:user_id])
  User Load (1.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ?  [["LIMIT", 1]]
=> nil
irb(main):005:0> session[:user_id] = User.first.id
  User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 1
irb(main):006:0> # 8.2.2.2
irb(main):007:0* @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: "kojimanotech", email: "kojimanotech@email.com", created_at: "2018-07-05 13:56:06", updated_at: "2018-07-05 13:56:06", password_digest: "$2a$10$rqZ1irlA2uVbSBFJF0jWrOUPKPqbowfdrWG3hmiKxWt...">
irb(main):008:0> @current_user ||= User.find_by(id: session[:user_id])
=> #<User id: 1, name: "kojimanotech", email: "kojimanotech@email.com", created_at: "2018-07-05 13:56:06", updated_at: "2018-07-05 13:56:06", password_digest: "$2a$10$rqZ1irlA2uVbSBFJF0jWrOUPKPqbowfdrWG3hmiKxWt...">

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

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

解答

_sample_app_sessionの値を削除してから画面を再読み込みしたものです。
新しいセッションIDが生成されていますが、ヘッダーが非ログイン状態のものになりました。
(他にもいろんなセッションがあるのは気にしないでくだされ…。)

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

解答

再ログインすることでヘッダーが元に戻ることを確認しました。

ブラウザ再起動については省略します。

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

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

解答

!を消してみます。

  # ユーザーがログインしていればtrue,その他ならfalseを返す
  def logged_in?
    current_user.nil?
  end

テストを実行することでREDになることが確認できます。

$ rails test test/integration/users_login_test.rb
(中略)

Failure:
UsersLoginTest#test_login_with_valid_information [/home/vagrant/tutorial2/sample_app/test/integration/users_login_test.rb:26]:
Expected exactly 0 elements matching "a[href="/login"]", found 1..
Expected: 0
  Actual: 1


bin/rails test test/integration/users_login_test.rb:19


Finished in 0.75131s
2 tests, 8 assertions, 1 failures, 0 errors, 0 skips



Finished in 0.762086s, 2.6244 runs/s, 10.4975 assertions/s.
2 runs, 8 assertions, 1 failures, 0 errors, 0 skips

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

解答

元に戻すだけなので省略。

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

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

解答

こんな聞き方するからredになると見せかけてgreenになるのか?とか思ったりしたのですが、
案の定redになりましたね。

$ rails test
Running via Spring preloader in process 12307
Started with run options --seed 53333

Run options: --seed 53333--=---=---=---=---=---=-] 0% Time: 00:00:00,  ETA: ??:??:??

# Running:

 FAIL["test_valid_signup_information", UserSignupTest, 0.8285849249996318]
 test_valid_signup_information#UserSignupTest (0.83s)6% Time: 00:00:00,  ETA: 00:00:        Expected false to be truthy.             ] 30% Time: 00:00:00,  ETA: 00:00:0        test/integration/users_signup_test.rb:32:in `block in <class:UserSignupTest>'.  23/11: [=================                     ] 47% Time: 00:00:00,  ETA: 00:00:..  23/13: [=====================                 ] 56% Time: 00:00:00,  ETA: 00:00:F 23/18: [=============================         ] 78% Time: 00:00:00,  ETA: 00:00:00.  23/15: [========================              ] 65% Time: 00:00:00,  ETA: 00:00:0Failure:: [==========================            ] 69% Time: 00:00:00,  ETA: 00:00:0UserSignupTest#test_valid_signup_information [/home/vagrant/tutorial2/sample_app/test/integration/users_signup_test.rb:32]:
Expected false to be truthy.


bin/rails test test/integration/users_signup_test.rb:21

.  23/21: [==================================    ] 91% Time: 00:00:00,  ETA: 00:00:0.  23/22: [====================================  ] 95% Time: 00:00:00,  ETA: 00:00:0.  23/23: [=====================================] 100% Time: 00:00:00, Time: 00:00:00
.
Finished in 0.93738s
23 tests, 59 assertions, 1 failures, 0 errors, 0 skips

assert is_logged_in?がfalseを返してエラーになってました。
sessionにuser_idをセットする処理をすっとばしちゃってるから
session確認したらエラーになって当たり前でしたね。

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

解答

テスト結果についてはほぼ自明n
普通のテキストエディタとかだとctrl+aしてからctrl+kとかctrl+qとかすると
できたりするのですが、私はvim使っているので、全ての行頭に#を付加する方法を紹介しようと思います。

ズバリ
gg0<ctrl+v>Gi#ZZ
です!w
gg:一行目に移動
0:行頭に移動
<ctrl+v>:矩形選択モード
G:行末に移動
i:挿入モード
#:#を挿入
:挿入モード解除
ZZ:保存して終了

コメントアウトを解除するときは
gg0GxZZ
です!
x:1文字削除
を利用します。

8.3 ログアウト

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

解答

[log out]をクリックすると、

  • ホーム画面に遷移
  • ヘッダーがログイン前の状態

になります。

リスト8.31で定義した処理の流れは

  1. ログインする
  2. ユーザー詳細画面に遷移する
  3. ログアウトしてホーム画面に遷移する

という流れです。各自確認してみてください。

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

解答

is_logged_inのパラメータが落ちます。
sessionは新しく別のができるみたいだけど、これで良いのかがちょっと不明です。
申し訳ありません。

内部の処理を想像できればだいたいどんなことするのかは検討つくとは思います。
実際実装できるかどうかは経験を積まないといけませんが、その検討がつくかつかないかは
エンジニアの自走力に大きく影響すると思います。

私もまだまだ未熟ですが、頑張っていきましょ!


Railsチュートリアルカテゴリの最新記事