##前提
・Railsチュートリアルは第4版
・今回の学習は3周目(9章以降は2周目)
・著者はProgate一通りやったぐらいの初学者
##基本方針
・読んだら分かることは端折る。
・意味がわからない用語は調べてまとめる(記事最下段・用語集)。
・理解できない内容を掘り下げる。
・演習はすべて取り組む。
・コードコピペは極力しない。
第8章はログインと認証システムの開発・第3段回目、基本的なログイン機構を実装していきます。(第9章でさらに発展させていきます)
情報技術の用語が飛び交いますので、それぞれの用語の意味・動作も理解しながら進めていきましょう。
本日のBGMは趣向を変えて。
TVアニメ「ゆるキャン△」オリジナル・サウンドトラック
やっと涼しくなってきました。キャンプに最適なシーズンです。コーディングで疲れた眼と頭のリフレッシュに行きましょう。
####【8.1.1 Sessionsコントローラ 演習】
1. GET login_pathとPOST login_pathとの違いを説明できますか? 少し考えてみましょう。
→ GETはログインページのビュー取得(newアクション)、POSTはフォームに入力したデータを送信してログインを実行(createアクション)。
2. ターミナルのパイプ機能を使ってrails routesの実行結果とgrepコマンドを繋ぐことで、Usersリソースに関するルーティングだけを表示させることができます。同様にして、Sessionsリソースに関する結果だけを表示させてみましょう。現在、いくつのSessionsリソースがあるでしょうか? ヒント: パイプやgrepの使い方が分からない場合は Learn Enough Command Line to Be Dangerousの Section on Grep (英語) を参考にしてみてください。
→ パイプ機能:(コマンド) | (コマンド) のようにコマンド同士を繋ぐ機能。
grepコマンド:ファイル中の文字列を検索するコマンド。
ということで下記。signupが入ってしまうのは仕方ない?
$ 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
####【8.1.2 ログインフォーム 演習】
1. リスト 8.4で定義したフォームで送信すると、Sessionsコントローラのcreateアクションに到達します。Railsはこれをどうやって実現しているでしょうか? 考えてみてください。ヒント:表 8.1とリスト 8.5の1行目に注目してください。
→ routesファイルのpost '/login', to: 'sessions#create'の一文でしょう。form_forで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: "2020-09-12 09:09:50", updated_at: "2020-09-12 09:09:50", password_digest: "$2a$10$hrOEzw0faSd4yurmH8bQJOnggeNnUqTZg33yE9g7Tnk...">
>> !!(user && user.authenticate("matigatteruyo"))
=> false
>> !!(user && user.authenticate("hogehoge"))
=> true
####【8.1.5 フラッシュのテスト 演習】
1. 8.1.4の処理の流れが正しく動いているかどうか、ブラウザで確認してみてください。特に、flashがうまく機能しているかどうか、フラッシュメッセージの表示後に違うページに移動することを忘れないでください。
→ 試してみましょう。違うページに行くとフラッシュが消えます。
####【8.2.1 log_in メソッド 演習】
1. 有効なユーザーで実際にログインし、ブラウザからcookiesの情報を調べてみてください。このとき、sessionの値はどうなっているでしょうか? ヒント: ブラウザでcookiesを調べる方法が分からない? 今こそググってみるときです! (コラム 1.1)
2. 先ほどの演習課題と同様に、Expiresの値について調べてみてください。
→ まとめて下の画像。Expires = 期限切れなので、緑の四角内です。ブラウザセッション終了時が有効期限になっていますね。
####【8.2.2 現在のユーザー 演習】
1. Railsコンソールを使って、User.find_by(id: ...)で対応するユーザーが検索に引っかからなかったとき、nilを返すことを確認してみましょう。
→ 下記
>> User.find_by(id: 8)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 8], ["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.2ms) 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.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2020-09-12 09:09:50", updated_at: "2020-09-12 09:09:50", password_digest: "$2a$10$hrOEzw0faSd4yurmH8bQJOnggeNnUqTZg33yE9g7Tnk...">
>> @current_user ||= User.find_by(id: session[:user_id])
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2020-09-12 09:09:50", updated_at: "2020-09-12 09:09:50", password_digest: "$2a$10$hrOEzw0faSd4yurmH8bQJOnggeNnUqTZg33yE9g7Tnk...">
####【8.2.3 レイアウトリンクを変更する 演習】
1. ブラウザのcookieインスペクタ機能を使って (8.2.1.1)、セッション用のcookieを削除してみてください。ヘッダー部分にあるリンクは非ログイン状態のものになっているでしょうか? 確認してみましょう。
→ やってみるだけ。非ログイン状態になりました。
2. もう一度ログインしてみて、ヘッダーのレイアウトが変わったことを確認してみましょう。その後、ブラウザを再起動させ、再び非ログイン状態に戻ったことも確認してみてください。注意: もしブラウザの [閉じたときの状態に戻す] 機能をオンにしていると、セッション情報も復元される可能性があります。もしその機能をオンにしている場合、忘れずにオフにしておきましょう (コラム 1.1)。
→ やってみるだけー。
####【8.2.4 レイアウトの変更をテストする メモと演習】
ここのdigestメソッドのコードの書き方は正直??状態。:を2つ書くのってどういう意味なんでしょうか。前からちょくちょく出てきてるけど。調べると、PHPの記法は出てくるけど、同じような意味にとっていいのだろうか。
テストのアサーションなんかは用語集にまとめてます。
1. 試しにSessionヘルパーのlogged_in?メソッドから!を削除してみて、リスト 8.23が redになることを確認してみましょう。
2. 先ほど削除した部分 (!) を元に戻して、テストが greenに戻ることを確認してみましょう。
→ まとめて。当然失敗します。ヘッダーの表示がログイン・非ログイン時で逆になっちゃうから。戻せばGREENです。
####【8.2.5 ユーザー登録時にログイン メモと演習】
この章ではいろんなヘルパーメソッドを定義していますね。どこで使うために、どこに定義しているの意識しながらコードを書きましょう。コントローラで使うのか、テストで使うのか等。
1. リスト 8.25のlog_inの行をコメントアウトすると、テストスイートは red になるでしょうか? それとも green になるでしょうか? 確認してみましょう。
→ REDになります。テストにログイン状態か確かめるコード書いているので。
2. 現在使っているテキストエディタの機能を使って、リスト 8.25をまとめてコメントアウトできないか調べてみましょう。また、コメントアウトの前後でテストスイートを実行し、コメントアウトすると red に、コメントアウトを元に戻すと green になることを確認してみましょう。ヒント: コメントアウト後にファイルを保存することを忘れないようにしましょう。また、テキストエディタのコメントアウト機能については Test Editor Tutorial の Commenting Out (英語) などを参照してみてください。
→ (Macの場合)command+Aで全選択、command+/でコメントアウト。当然コメントアウトの前後でRED/GREENになります。
####【8.3 ログアウト メモと演習】
1. ブラウザから [Log out] リンクをクリックし、どんな変化が起こるか確認してみましょう。また、リスト 8.31で定義した3つのステップを実行してみて、うまく動いているかどうか確認してみましょう。
→ ちゃんと動きます。
2. cookiesの内容を調べてみて、ログアウト後にはsessionが正常に削除されていることを確認してみましょう。
→ 削除されてます。
###第8章まとめ
・sessionメソッドで一時的な状態保存。
・ログインではActive RecordのUserモデルを使わないので、関連づけられたエラーメッセージは使えない。
・flash.nowでrenderしたページのみフラッシュメッセージを表示。
・form_forはform_withに置き換わってるようなので参考までに。
・renderとredirect_toの使い分け。
・flashメッセージを表示。
・統合テストでログインまわりの実装を一通りテスト(ログイン/ログアウトできているか、ヘッダーは切り替わっているか)
この章は大きなエラーなく進められました。次の9章から発展的な機構を導入していきます。遂に1周しかしていない章に入っていきますね!気合入れていきましょう!
⇨ 第9章へ!
⇦ 第7章はこちら
学習にあたっての前提・著者ステータスはこちら
####なんとなくイメージを掴む用語集
・ステートレス・プロトコル
状態の保持をしない独立した情報のやりとり。ログイン機能に例えると、一回ブラウザを閉じて再度入り直すと、ログインし直しになる。
・セッション(session)
一連の通信のこと(ログインからログアウトまで等)。ェブサイトでは、初めて訪問した場合にブラウザのcookieに書き込まれる識別子のこと。
・cookie
HTTPにおけるウェブサーバとウェブブラウザ間で状態を管理する通信プロトコル、またそこで用いられるウェブブラウザに保存された情報のこと。ECサイトの買い物カゴやログイン機能等で使われている。溜まってきたなと思ってブラウザの設定とかから消せるアレ。
・assert_redirected_to
このアサーションの直前で呼び出されたリダイレクト先と、to以下のリダイレクト先が一致するかどうかテストする。
・follow_redirect!
実際にそのページに移動する。移動した先で他の要素をテストする際に利用。