演習1
1,
GET login_pathとPOST login_pathとの違いを説明できますか? 少し考えてみましょう。
まずはGETとPOSTの違いを知る必要があります
分かりやすい話としてはこちらを読むのが一番分かりやすいです
GETとPOSTの違いを理解したところで
GET login_pathは
→login_pathを表示する。つまりここではsessions/new.html.erbを表示するためです
POST login_pathは
→login状態を作る
ということです。
個人的には誰にでも見られても良いページなどの表示はGETを使用し
データベースの保存などの操作が加わるなど、機密性の高い操作の場合はPOSTを使用する
というイメージです。
2,
ターミナルのパイプ機能を使ってrails routesの実行結果とgrepコマンドをつなぐことで、Usersリソースに関するルーティングだけを表示できます。同様にして、Sessionsリソースに関する結果だけを表示させてみましょう。現在、いくつのSessionsリソースがあるでしょうか? (ヒント: パイプやgrepの使い方が分からない場合は 『コマンドライン編』の 「grepで検索する」を参考にしてみてください。)
以下のようにパイプを使用します
$ rails routes | grep users
signup GET /signup(.:format) users#new
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)
演習2
1,
リスト 8.4で定義したフォームで送信すると、Sessionsコントローラのcreateアクションに到達します。Railsはこれをどうやって実現しているでしょうか? 考えてみてください。(ヒント:表 8.1とリスト 8.5の1行目に注目してください。
リスト8.4のこの部分に注目です
<%= form_with(url: login_path, scope: :session) do |f| %>
form_withはPOSTメソッドを生成します。
引数を見てみると、sessionコントローラーのlogin_pathが設定されているので
上記のPOSTのcreateアクションに到達するというわけです
演習3
1,
Railsコンソールを使って、表 8.2のそれぞれの式が合っているか確かめてみましょう. まずはuser = nilの場合を、次にuser = User.firstとした場合を確かめてみてください。(ヒント: 必ず論理値オブジェクトとなるように、4.2.2で紹介した!!のテクニックを使ってみましょう。例: !!(user && user.authenticate('foobar')))
rails c
Loading development environment (Rails 7.0.4.3)
user = nil
=> nil
!!(user && user.authenticate('foobar'))
=> false
user = User.first
!!(user && user.authenticate('foobar'))
=> false
#演習の例に沿って'foobar'としていますが、最初のユーザーのpasswordが別のパスワードの場合
falseになります
!!(user && user.authenticate('password'))
=> true
#正しいパスワードを入力した場合trueになります
演習4
1,
8.1.4の処理の流れが正しく動いているかどうか、ブラウザで確認してみてください。特に、flashがうまく機能しているかどうか、フラッシュメッセージの表示後に違うページに移動することを忘れないでください。
ログインページにてわざと登録されていない情報を入力し、フラッシュメッセージを出現させましょう
他のページに遷移したとき、フラッシュメッセージが表示されていなければOKです
演習5
1,
有効なユーザーで実際にログインし、ブラウザでcookiesの情報を調べてみてください。このとき、sessionの値はどうなっているでしょうか? ブラウザでcookiesを調べる方法が分からなければ、今こそググってみるときです!(コラム 1.2)
chromeの場合は以下の記事を参照などにして確認できる
https://www.koikikukan.com/archives/2017/12/13-000300.php
らしいのですが、2023年9月現在、この記事通りに検索してみてもcookieはサードパーティーのcokkie
などに変わり、いろいろ情報を調べてみたのですが、有効期限(Expires)などが表示される情報は得られず、chromeがcookieを廃止していることと何か関係しているのではないかと思うのですが、下記画像にあるような情報は得られませんでした。
chormeでcookie情報の使い方を知っている方情報提供頂けると幸いです
一応検証ツールではcookieを調べられるみたいです
丈夫にあるアプリケーションをクリックするとcookie情報を調べられます
2,
上の演習課題と同様に、Expires(有効期限)の値について調べてみてください。
上記の画像を見るとExpiresはセッションと書いてあるのでセッション終了時ということですね
演習6
1,
Railsコンソールを使って、User.find_by(id: ...)で対応するユーザーが検索に引っかからなかったとき、nilを返すことを確認してみましょう。
現在私のdbにはid2までのuserしかいません。
User.all
User Load (0.2ms) SELECT "users".* FROM "users"
=>
[#<User:0x00007fc1b2854d48
id: 1,
name: "Rails Tutorial",
email: "example@railstutorial.org",
created_at: Mon, 18 Sep 2023 07:33:00.160796000 UTC +00:00,
updated_at: Mon, 18 Sep 2023 07:33:00.160796000 UTC +00:00,
password_digest: "[FILTERED]">,
#<User:0x00007fc1b091f6f8
id: 2,
name: "Nanoha",
email: "example@gmail.com",
created_at: Mon, 18 Sep 2023 07:52:47.624920000 UTC +00:00,
updated_at: Mon, 18 Sep 2023 07:52:47.624920000 UTC +00:00,
password_digest: "[FILTERED]">]
なのでidが3という架空のuserを検索してみましょう
User.find_by(id: 3)
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
=> 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.1ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ? [["LIMIT", 1]]
=> nil
session[:user_id] = User.first.id
User Load (0.1ms) 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:0x00007f941af05518
...
@current_user ||= User.find_by(id: session[:user_id])
=>
#<User:0x00007f941af05518
演習7
1,
演習8.2.1.1でも触れたブラウザのcookieインスペクタ機能を使って、セッション用のcookieを削除してみてください。ヘッダー部分にあるリンクは非ログイン状態のものになっているでしょうか? 確認してみましょう。
cookieの削除方法はいろいろありますが、ここでは検証ツールを使用したcookieの削除方法で試してみます
右クリックで検証ツールを開きアプリケーションを選択すると、cookieの情報があるので、その左下のマークをクリックするとcookieを削除できます
再読み込みしてログイン前の画面に戻っていることを確認しましょう
2, もう一度ログインしてみて、ヘッダーのレイアウトが変わったことを確認してみましょう。その後、ブラウザを再起動させ、再び非ログイン状態に戻ったことも確認してみてください。注意: もしブラウザの[閉じたときの状態に戻す]機能をオンにしていると、セッション情報も復元される可能性があります。もしその機能をオンにしている場合、忘れずにオフにしておきましょう(コラム 1.2)。
単純にもう一度ログインしてみてログイン後の画面になることを確認します。その後、再びブラウザを再起動しましょう。
3,
本文でも述べたように、menu.js(リスト 8.30)のコードには同じコードが何度も繰り返し書かれています。コードの重複をほぼ排除したリファクタリング済みのコード(リスト 8.32)を適用してから、メニューのトグル機能が引き続き正常に動作することを、画面の手動操作によるテストで直接確認してみてください。
リファクタリングされたリスト8.32のコードに書き換え、rails testを実行します。
エラーが出ていないことを確認しましょう。
演習8
1,
リスト 8.15の8行目にあるif userから後ろをすべてコメントアウトして、入力されたメールアドレスとパスワードの組み合わせによる認証が行われていない場合でもテストがパスしてしまうことを確認してください(リスト 8.37)。パスしてしまう理由は、ログインが失敗した場合のテスト(リスト 8.9)に「メールアドレスは正しいがパスワードが誤っている」ケースが含まれていないからです。このケースが含まれていないのは重大な手抜かりですので、リスト 8.38の(コードを書き込む)を正しいメールアドレスを定義するコードに置き換え、ログインが失敗した場合のテストを「正しいメールアドレスと誤ったパスワードでログインしようとした場合のテスト」となるように修正しましょう。修正したテストが red (失敗)することを確認し、次に先ほどの8行目以降のコメントアウトを元に戻すと green (パス)することを確認してください。この演習の修正は重要なので、この後の 8.3のメインのコードにも修正を反映してあります。
まず以下をコメントアウトします
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user #&& user.authenticate(params[:session][:password]) ここまでコメントアウト
reset_session
log_in user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new', status: :unprocessable_entity
end
end
def destroy
end
end
次に、指定されたコードを使い、「コードを書き込む」の部分を以下のようにします
users_login_test.rb
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "login with invalid information" do
get login_path
assert_template 'sessions/new'
post login_path, params: { session: { email: @user.email ,#ここを変更
password: "invalid" } }
assert_response :unprocessable_entity
assert_template 'sessions/new'
assert_not flash.empty?
get root_path
assert flash.empty?
end
end
この状態でrails testを実行し、エラーが出ることを確認します。
先ほどのコメントアウトを外し、もう一度テストし、エラーが消えていることを確認しましょう。
2,
safe navigation演算子(または“ぼっち演算子”)と呼ばれる&.を用いて、リスト 8.15の8行目の論理値(boolean値)の条件式を、リスト 8.3919 のようにシンプルに変えてください。Rubyのぼっち演算子を使うと、obj && obj.methodのようなパターンをobj&.methodのように凝縮した形で書けます。変更後も、リスト 8.38のテストがパスすることを確認してください。
リストのコードを使用し、rails testを行い、エラーが出なければOKです
演習9
1,
リスト 8.40のlog_inの行をコメントアウトすると、テストスイートは red になるでしょうか? それとも green になるでしょうか? 確認してみましょう。
以下のような結果になります。結論RED
rails t
Started with run options --seed 36588
FAIL UsersSignupTest#test_valid_signup_information (1.14s)
Expected false to be truthy.
test/integration/users_signup_test.rb:32:in `block in <class:UsersSignupTest>'
23/23: [=================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.20170s
23 tests, 69 assertions, 1 failures, 0 errors, 0 skips
2,
現在使っているテキストエディタの機能を使って、リスト 8.40をまとめてコメントアウトできないか調べてみましょう。また、コメントアウトの前後でテストスイートを実行し、コメントアウトすると red に、コメントアウトを元に戻すと green になることを確認してみましょう。(ヒント: コメントアウト後にファイルを保存することを忘れないようにしましょう。また、テキストエディタのコメントアウト機能については『テキストエディタ編』の 「コメントアウト機能」などを参照してみてください。)
「ctrl」 + [A]
で全てを選択し、「ctrl」+ 「/」でコメントアウトが出来ます。
演習10
1,
ブラウザで「Log out」リンクをクリックしたときに、Webサイトのレイアウトが正しく切り替わることを確認してください。このログアウト時のレイアウト切り替えと、リスト 8.46のテストの末尾3行にどのような対応関係があるかを考えて答えてください。
ログアウトする
2,
リスト 8.46にある2つのテストの内容が少し増えてしまいました。このままだとテストのメンテナンスがやりにくくなる可能性があります。テストを分割する戦略はいくつか考えられますが、その1つは、関連するテストごとにRubyのクラス(4.4)を別途作る方法です。クラスを作ると、テストに必要なsetupメソッドの中で関連する部分を継承(4.4.2)で再利用できます。
ここで重要なのはリスト 8.48でハイライトされているsuperです。superは、現在のクラスのスーパークラス(クラス階層の1つ上にあるクラス)にある、対応するsetupメソッドを呼び出します。
この演習問題のトピックはやや高度なので、基本的にリスト 8.48のテストコードが green になることを確認できればOKです。しかし、このテストコードを理解してみたい方はぜひじっくり読んでみてください。リファクタリング前のリスト 8.46と注意深く見比べてみると、以前よりもずっと多くのことを発見できるようになった自分に驚くことでしょう。テストのリファクタリングについては、この後の 11.3.3、 12.3.3、 13.3.5で詳しく扱います。