ume

rails routing error

前書き

初歩的なエラーによくハマる傾向があり 原因を深く特定せず解決策を探しその場しのぎみたいなやり方が多いのでまた同じエラーに遭遇した時に解決策探してを繰り返し時間効率が悪いので、今回はエラーの原因を特定し、エラーに遭遇する前にそもそもエラーを起こさないようにするために原因を考えてみる。

目次

①エラーの発生.
②エラーの原因.
③まとめ.

エラーの発生

エラーの原因

↑の画像で正しいリクエスト(GET /users)がルーティングファイルにあるVerbとURL Patternに合致するとルーティングファイルのController#Action(users#index)を表示する. usersフォルダのindexファイルが表示される.

エラーの原因.
間違ったリクエストが送られたり、 ルーティングファイルにそもそも存在しないリクエストが送られてくると今回のようなエラーが表示される.

ブラウザーから送られてくる間違ったリクエストとは? 例えば ルーティングファイルのVerbにGET、URL Pattern /usersがあるが ブラウザーから送られてくるリクエストが POST /users/1みたいなリクエストだと ルーティングファイルに存在しないためエラーになる.

まとめ

もしルーティングエラーが発生した場合は やること2つ①rails routesで今自分が使えるルーティングの把握.
②自分がどんなリクエストを飛ばしているかを確認しその該当するものがルーティングファイルに存在するか確認する.

レビュー機能の実装(データの関連付け)

前書き

ECサイトAmazonのようなアプリ)を制作途中でこのようなレビュー投稿機能を実装しようとしています。実装過程で自分にとって新しい概念が出てきましたので記録するとともに、記事を見ている方の勉強の参考になればと思い記事に残しています.

実装までの大まかな手順.
①レビュー用のモデルの作成.
②レビューと商品・ユーザーの関連付けを行う.
③レビュー用のコントローラーの作成と編集 #私にとって新しい概念が出てきました.
④ルーティングの作成.
⑤viewファイルの作成と編集.

今回の記事主に③についての紹介ですが一通りざっくりと全体的な流れも紹介させていただきます.

①レビュー用のモデルの作成

rails初学者の方は一度は疑問に思ったことがあると思うのですが「なぜ複数個モデルを作成する必要があるの?」と思ったことがあるのではないでしょうか?以下のようなコマンドを使用したことが多いと思います.

rails g model ○○

なぜ1つのアプリケーションを作成する過程で複数のモデルが必要かというと 「データベースのテーブル毎にモデルを作る必要があるからです」.
またモデルの役割は「データベースとのやり取りを行うクラス」です

②レビューと商品・ユーザーの関連付けを行う.

①で作ったモデルは他に作成したモデルとどのような関係性があるのかを明記してあげる. 関連づけをする理由としてはデータベースに情報を登録する時とかにコードを書く量が減るので可読性が上がったりコードが分かりやすくなる.
↓モデル間の関係性を明記 例

class Product < ApplicationRecord
  belongs_to :category
  has_many :reviews
end

③レビュー用のコントローラーの作成と編集.

1つのアプリケーションに複数のコントローラを作成する理由は「機能ごとにコントローラを分けることによってメンテナンス性をあげる」.
例えば1つのファイルにhtml.scc.javascriptのコードが混じっていたら読みにくくて何をしたいのかっていうのが理解しにくくなる。同じように1つのコントローラーで複数の機能を実装しようとすると後から見直した時に何がしたいのか分かりにくくなる.
新しい概念.
関連づけをしたときに複数のテーブルから情報を取得する方法.
例えば 2つテーブルがあったとして「冷蔵庫のレビュー」を知りたいとなった場合で

モデルの関連付け「なし」のときのデータの取得方法と モデル間の関連付け「あり」のときのデータの取得方法を比べてどのような違いがあるか見ていきたいと思います.

関連付けなしパターン

@product = Product.find(1) #プロダクトテーブルの(1)に該当する情報を@productに代入する
@reviews = Review.where(product_id: @product.id) #productテーブルの際と同じようにReviewテーブルの中から該当する情報を取得してきて@productに代入する

関連付けありのパターン

 review.rb
class Review < ActiveRecord::Base
  belongs_to :product
end

 product.rb
class Product < ActiveRecord::Base
  has_many :reviews
end
@product = Product.find(1)
@reviews = @product.reviews # 直感的なコードになる

↑このとき @reviews = @product.reviewsのreviewsの書き方には2種類ある. 1つ目.
モデルにreviewsというメソッドを定義する.

def reviews.  
  Review.find(1)
end 

2つ目1行で表す

@reviews = @product.reviews.find(1)

この時reviewsの所は先頭小文字のテーブル名で、語尾にsがつく

まとめ

関連付けによりデータベースからのデータの取得が関連付けなしと少し違う.

リモートにgit pushできない

前書き

先日rails tutorial10章を勉強をしていて、ひと段落ついたのでgit pushでリモートリポジトリに送ろうとしたのですがエラーが出力されpushできませんでした。今はエラーを解決したのですが「なぜエラーが起こったのか」をシェアすることで自分のgitの理解度を上げるとともにこの記事に辿り着いた私と同じようにgit pushできなくて困っている方の少しでも参考になればと思い記事に残しています. エラーまでに私が行ったこと コミットをした後に何か間違いに気づきgit reset --hard 過去のコミットIDに戻りました.

目次

①エラーの発生.
②エラーの原因.
③解決策.

①エラーの発生

hint: Updates were rejected because the tip of your current branch is behind

英語の直訳.
リモートリポジトリの更新ができなかったよ。だってあなたのブランチの最新のコミットが遅れている. tipは「先っぽ」という意味でブランチの先っぽ=最新のコミット。behindは「後ろ」という意味ですがここでは最新の後=「遅れている」と解釈しました.

エラーの原因

要はエラーが出たのはリモートリポジトリとローカルリポジトリの最新情報が異なっているため。どうやら異なりかたの種類は2通りぐらいあるようです.

master    a --- b --- c --- d --- e
(リモート)
  
master    a --- b --- c --- d --- e
(ローカル)     

↑ローカルとリモートのリポジトリそれぞれのイラストの例です。アルファベットがコミットを表しています.
初めリモートリポジトリととローカルリポジトリが同じだとします。そして今自分はローカルのeのbranchにいるとします。 eのコミットが終わった際何かの間違いに気づいてe⇨ローカルのcの状態に戻りたいとします。 その際git reset --hard cのコミットIDで戻ったとします。それが↓の状態

master    a --- b --- c --- d --- e
(リモート)
  
master    a --- b --- c  
(ローカル)     

このローカルのcの状態からcに変更を加えてコミットしたとします。するとdではなく新しいコミットid、fというコミットができます。補足コミットするたびにコミットIDは毎回違うということを学びました.

master    a --- b --- c --- d --- e
(リモート)
  
master    a --- b --- c --- f
(ローカル)     

この状態でpushすると

hint: Updates were rejected because the tip of your current branch is behind

ローカルが遅れているからpushできないと言われる.

③解決策.

このエラーはリモートリポジトリの最新の状態をローカルにpullしていないにも関わらず、ローカルでpushしようとすると発生するエラーで、こまめにpullすることで防げるエラーである.

初めてのローカル環境構築(サーバーサイド)

本記事の対象者

①これからローカルで環境構築をしようとされる方で環境構築の概要と準備物が知りたい方

目次

①環境構築と必要なもの.
②ローカル環境と総合開発環境の違い.

環境構築と必要なもの.

webサイトやwebアプリ作成に必要なものを自分のPCに取り入れること=自分のPC内に開発環境を構築すること.
どんなものを取り入れる必要があるのか.
①PC.
⇨PCはMacWindowsのどちらでも良い. ⚠️PCのバージョンが古すぎる場合、「ソフトウェアに対応しておらず利用できない」といった問題が発生する可能性があります.
テキストエディタ.
プログラミング言語を書くためのもの. 通常字を書くときは「メモ帳」などを使いますがプログラミング言語を書く場合はエディタを使います。メモ帳=エディタのイメージです.
ブラウザー.
プログラミング言語を人間がわかるように翻訳し表示させる場所 ④webサーバー.
⇨サンタさんのイメージ、要は欲しいものをくれるイメージ.
ブラウザーから「amazonのページが見たい」というお願いをするとwebサーバーが『はいどうぞ』と欲しいものをくれる.
代表的なWebサーバーにはApacheやNginxなどがあります。

⑤サーバーサイド言語.
⇨動的サイトを作成する際サーバーサイド言語で書く必要がある. 動的サイトとはユーザーの操作の仕方によって表示される画面が違うサイトamazonなど サーバーサイド言語:サーバー側で動く言語(例:PHPRubyPythonなど) ⑥データベース.
⇨データの集まり、 MySQLPostgreSQLなどがある.

ローカル環境と総合開発環境の違い

注意:ローカル環境で開発したからといって本番環境で必ず動く保証はありません。ただローカル環境で開発した方が以下のメリットがあります.
①オフラインで開発できる.
②データベースを使用できる選択肢が多い.
③本番環境で動く可能性が高い.

conflictの深掘り

#前書き 普段gitを何気なく使っていますがconflictという言葉とざっくりとした意味は知っているのですがどういう時にconflictが起きるのか具体的に理解していなかったので今回は実際に意図的にconflictを起こし挙動を詳しくみていきたいと思います。

目次

①コンフリクトとは.
②なぜコンフリクトは起こるのか?.

コンフリクト

Gitにおいて、コミット履歴を持つ2つ以上のブランチを統合する場合には、競合 = コンフリクト が起こる場合があります。 例えば2つのブランチをマージする際に両方のブランチで同じ行を編集している場合はコンフリクトが発生するため、Gitは自動的にマージをせずに開発者自身にコンフリクトの解消を求めます。 コンフリクトしていない場合はGitが自動的にマージを行い、コミットもされます。コンフリクトしている場合は、競合の解消、解消後のマージの両方を開発者自身が行う必要があります。

下準備

1つのテキストファイルを持つリポジトリを作成します。

% mkdir conflict-sample
% cd conflict-sample
% git init
Initialized empty Git repository in /xxxx/conflict-sample/.git/
% touch test.txt
% cat << EOF > test.txt
Line 1 
Line 2
Line 3
EOF 
% cat test.txt 
Line 1
Line 2
Line 3
% git add test.txt
% git commit -m "first commit"
[main (root-commit) 0049849] first commit
 1 file changed, 3 insertions(+)
 create mode 100644 test.txt
% git log --graph --pretty=format:"%h %s"
* 0049849 first commit
% git status
On branch main
nothing to commit, working tree clean

注意: ターミナルで実行したヒアドキュメントをそのまま貼るとうまく解釈されず、フォーマットがおかしなことになったので一部修正しています。

mainブランチに1つコミットが入りました。

コンフリクトが発生しない場合

まずはコンフリクトが発生しない場合の動きを見てみます。 mainブランチから新しいブランチ no-conflict を作成します。

% git branch
* main
% git switch -c no-conflict
Switched to a new branch 'no-conflict'
% git log --graph --pretty=format:"%h %s %d"
* 0049849 first commit  (HEAD -> no-conflict, main)

mainとno-conflictは同じ状態になっています。

ここでmainブランチに変更を加えます。4行目を追加します。

% git switch main
Switched to branch 'main'
% cat << EOF >> test.txt
Line 4
EOF
% cat test.txt 
Line 1
Line 2
Line 3
Line 4
% git add test.txt 
% git commit -m "Line4を追加(mainブランチ)" 
[main 218ca30] Line4を追加(mainブランチ)
 1 file changed, 1 insertion(+)

続いてno-conflictブランチにも変更を加えます。1行目に修正を加えます。

% git switch no-conflict
Switched to branch 'no-conflict'
% cat << EOF > test.txt
Line 1 no-conflict
Line 2
Line 3
EOF
% cat test.txt 
Line 1 no-conflict
Line 2
Line 3
% git diff
diff --git a/test.txt b/test.txt
index 6ad36e5..6b03856 100644
--- a/test.txt
+++ b/test.txt
@@ -1,3 +1,3 @@
-Line 1
+Line 1 no-conflict
 Line 2
 Line 3
% git add test.txt 
% git commit -m "Line 1の末尾にブランチ名を追加(no-conflictブランチ)"
[no-conflict ee25571] Line 1の末尾にブランチ名を追加(no-conflictブランチ)
 1 file changed, 1 insertion(+), 1 deletion(-)

2つのブランチの履歴は以下のようになっています。

% git log --graph --pretty=format:"%h %s %d" main no-conflict
* ee25571 Line 1の末尾にブランチ名を追加(no-conflictブランチ)  (HEAD -> no-conflict)
| * 218ca30 Line4を追加(mainブランチ)  (main)
|/  
* 0049849 first commit

では、mainブランチにno-conflictブランチをマージしてみます。

% git switch main
Switched to branch 'main'
% git merge no-conflict
Auto-merging test.txt
Merge made by the 'recursive' strategy.
 test.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
% cat test.txt 
Line 1 no-conflict
Line 2
Line 3
Line 4

コミットメッセージを修正するための画面が開くものの、自動でマージされました。

履歴は以下のようになっています。

% git log --graph --pretty=format:"%h %s %d" main no-conflict
*   2c494a9 Merge branch 'no-conflict'  (HEAD -> main)
|\  
| * ee25571 Line 1の末尾にブランチ名を追加(no-conflictブランチ)  (no-conflict)
* | 218ca30 Line4を追加(mainブランチ) 
|/  
* 0049849 first commit

2つのブランチで、それぞれ違う行に対して変更が行われたため競合は発生しません。 mergeコマンドを実行するだけで、マージ、コミットまでされています。

コンフリクトが発生する場合

本題のコンフリクトが発生する場合です。

mainブランチから conflict ブランチを作成します。

% git switch main
Already on 'main'
% git switch -c conflict
Switched to a new branch 'conflict'
% git log --graph --pretty=format:"%h %s %d"
*   2c494a9 Merge branch 'no-conflict'  (HEAD -> conflict, main)
|\  
| * ee25571 Line 1の末尾にブランチ名を追加(no-conflictブランチ)  (no-conflict)
* | 218ca30 Line4を追加(mainブランチ) 
|/  
* 0049849 first commit

2つのブランチの同じ行に、それぞれ違う修正を加えます。 今回はそれぞれのブランチに5行目を追加します。

まずはmainブランチで5行目を追加します。

% git switch main
Switched to branch 'main'
% cat << EOF >> test.txt
Line 5 main
EOF
% cat test.txt 
Line 1 no-conflict
Line 2
Line 3
Line 4
Line 5 main
% git add test.txt
% git commit -m "5行目を追加(mainブランチ)"
[main 7118de9] 5行目を追加(mainブランチ)
 1 file changed, 1 insertion(+)

続いてconflictブランチで5行目を追加します。

% git switch conflict
Switched to branch 'conflict'
% cat << EOF >> test.txt
Line 5 conflict
EOF
% cat test.txt 
Line 1 no-conflict
Line 2
Line 3
Line 4
Line 5 conflict
% git add test.txt
% git commit -m "5行目を追加(conflictブランチ)"
[conflict 5155112] 5行目を追加(conflictブランチ)
 1 file changed, 1 insertion(+)

2つのブランチの履歴は以下のようになっています。

% git log --graph --pretty=format:"%h %s %d" main conflict 
* 5155112 5行目を追加(conflictブランチ)  (HEAD -> conflict)
| * 7118de9 5行目を追加(mainブランチ)  (main)
|/  
*   2c494a9 Merge branch 'no-conflict' 
|\  
| * ee25571 Line 1の末尾にブランチ名を追加(no-conflictブランチ)  (no-conflict)
* | 218ca30 Line4を追加(mainブランチ) 
|/  
* 0049849 first commit 

マージする

では、mainにconflictブランチをマージしてみます。

% git switch main
Switched to branch 'main'
% git merge conflict
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトしました。同じ行が変更されているため、Gitでは2つの変更をどのようにマージすればいいのかがわかりません。よって人間の手で解決する必要があります。メッセージを詳しく確認します。

CONFLICT (content): Merge conflict in test.txt 「test.txtでコンフリクトが起きています。」ということが言われています。

Automatic merge failed; fix conflicts and then commit the result. 「自動マージは失敗しました。コンフリクトを解消し、その結果をコミットしてください。」と言われています。

この時の状態を見て見ましょう。

% git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")

You have unmerged paths. ということで、未マージのものがあるということが言われています。

test.txtの中身も見てみましょう。

% cat test.txt
Line 1 no-conflict
Line 2
Line 3
Line 4
<<<<<<< HEAD
Line 5 main
=======
Line 5 conflict
>>>>>>> conflict

上記のように、マージしたときにコンフリクトがある場合、ファイルにもコンフリクトしている部分がわかるように変更が入っています。 コフリクトが発生した時の流れは、マージ(コンフリクトが発生、ファイル自体にもコンフリクトである部分がわかるように変更が入る) -> コンフリクトを解消する(ファイルを修正) -> コミットする、となります。

<<<<<<< HEAD から >>>>>>> conflict の間が実際にコンフリクトしている部分です。この部分を実際にファイルを編集することによって正しい状態にすることがコンフリクトの解消になります。

ここだけ抜き出して詳しくみてみましょう。

コンフリクト箇所を詳しくみてみる

<<<<<<< HEAD
Line 5 main
=======
Line 5 conflict
>>>>>>> conflict

<<<<<<<、 =======、 >>>>>>> を3wayマージマーカラインと言ったり、マージマーカと言ったりするようです(オライリー実用Git 』より)。 人が読むことが意図されて装飾されています。

まず、<<<<<<<から =======までの部分が、mainブランチでの変更箇所になります。

<<<<<<< HEAD
Line 5 main
=======

次に、=======から>>>>>>>までの部分が、conflictブランチでの変更箇所になります。

=======
Line 5 conflict
>>>>>>> conflict

HEAD がついている方が、今チェックアウトしているブランチ(=mainブランチ)の変更点となります。GitにおけるHEADは、現在チェックアウトしているブランチの最新コミットを指します。現在チェックアウトしているブランチ(=mainブランチ)の最新コミット(まだマージコミットはされていないので、この段階の最新コミットは7118de9)との差分、という意味ですね。

コンフリクトの解消

とうとうコンフリクトの解消をしてみます。 今回は Line 5 main と Line 5 conflict がコンフリクトしているわけですが、どちらのブランチでも同じ変更を入れているので、末尾のブランチ名を削って Line 5 だけにしてしまいましょう。 ターミナルでやるのが面倒になってきたので、テキストファイルを開いて修正します。

今こうなっているものを

Line 1 no-conflict
Line 2
Line 3
Line 4
<<<<<<< HEAD
Line 5 main
=======
Line 5 conflict
>>>>>>> conflict

以下のようにします。

Line 1 no-conflict
Line 2
Line 3
Line 4
Line 5

<<<<<<< HEAD から >>>>>>> conflict までの間をバッサリ消して、 Line 5 にしました。 コンフリクトを解消できました!

コンフリクトが発生せずに自動マージされた場合はコミットまで行われましたが、コンフリクトが発生した場合は、自分でコミットまで行う必要があります。

まずは今の状態を確認します。

% git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")

use "git add <file>..." to mark resolution とあります。 「"git add ..." を使って、解決したとマークしてくれ(教えてくれ)」と言われています。addしてみます。

% git add test.txt 
% git status
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
    modified:   test.txt

メッセージが変わりました。 All conflicts fixed but you are still merging. 「全てのコンフリクトは解消されました。が、まだマージ作業中です。」 use "git commit" to conclude merge 「"git commit"を使ってマージを完了してください」 コミットしましょう。

% git commit
[main 11cc5d4] Merge branch 'conflict'

コミットメッセージを修正するための画面が開きますが、デフォルトでメッセージが入っていますので、そのまま変更せずにコミットすることができます。

履歴やファイルを見てみます。

% cat test.txt 
Line 1 no-conflict
Line 2
Line 3
Line 4
Line 5

% git log --graph --pretty=format:"%h %s %d" main conflict 
*   11cc5d4 Merge branch 'conflict'  (HEAD -> main)
|\  
| * 5155112 5行目を追加(conflictブランチ)  (conflict)
* | 7118de9 5行目を追加(mainブランチ) 
|/  
*   2c494a9 Merge branch 'no-conflict' 
|\  
| * ee25571 Line 1の末尾にブランチ名を追加(no-conflictブランチ)  (no-conflict)
* | 218ca30 Line4を追加(mainブランチ) 
|/  
* 0049849 first commit

conflictブランチが無事、mainブランチにマージされました!

マージコミットを見てみましょう。

 % git show 11cc5d4
commit 11cc5d41665f44c56bf2de5f95aa783c4c7e7964 (HEAD -> main)
Merge: 7118de9 5155112
Author: chihiro <xxxx>
Date:   Fri Aug 20 08:18:01 2021 +0900

    Merge branch 'conflict'

diff --cc test.txt
index 1ff80e2,7d68217..1ac3a4d
--- a/test.txt
+++ b/test.txt
@@@ -2,4 -2,4 +2,4 @@@ Line 1 no-conflic
  Line 2
  Line 3
  Line 4
- Line 5 main
 -Line 5 conflict
++Line 5

diff 部分を見ると、 Line 5 mainLine 5 conflict が削除され、 Line 5 が追加された、と表現されています。

コンフリクトは良くないもの?

そんなことはありません(と私は思っています)。複数人で並行開発をしていればコンフリクトは普通に起こります。ですが、コンフリクトの解消をミスしてしまう(他の人が書いたコードを消してしまったり、意図しない修正をしてしまう)とバグとなってしまいますし、コンフリクトの内容が複雑であればあるほど解消に時間がかかる、というのも事実ではあると思います。そのため、詳しくは述べませんが以下のようなやり方(他にもいろいろあると思います)を部分的にでも取り入れて、不要なコンフリクトはなくすというのも大事だと思います。

  • feature flag を使うなどして、こまめに中央ブランチにマージする(=ビッグバンマージを避け、コンフリクトの量を減らす)
  • コンフリクトが起こっている部分の開発を担当したメンバーとペアでコンフリクトの解消をする(=コンフリクトの解消ミスを抑制)
  • ペアプロ、モブプロなどを取り入れることで並行作業を減らす(=そもそもコンフリクトが起こる機会を減らす)

最後に

大分長くなってしまいましたが、シンプルなコンフリクトの例を用いてまとめました。知ることによって不安が減ると思うので、よくわからないな〜と思っている方はぜひ自分の環境でやってみてほしいと思います。

rails tutorial 10章 認可について

前書き

記事の対象者⇨rails tutorial(10章)に苦戦している方.
何のための記事か⇨認可について.
記事を書いている人→rails tutorialを学んでいる初学者(プログラミング歴8ヶ月程).

目次

①認可とは.
②認可の実装手順.
③認可を実装してみる.

認可とは

①認可とは、正しいユーザー(ログインしているユーザーだけ)が正しい情報にアクセスできる.
要は「自分のページに誰でもアクセスさせないようにする」 こういうTwitterのようなアプリがあり上の画面は自分自身のアカウントページです。 このページを表示するにはURLの語尾に

amazonaws.com/users/101

users/101と入力すると表示されます このページは私しか操作できないようにするべきです。なぜならば第三者が私のユーザー名の更新やパスワードの更新ができてしまうからです。そこで誰でもamazonaws.com/users/101にはアクセスできないようにする仕組みが「認可」です.

②認可の実装手順

①もしログインしていなかった場合ログインするように促す.
②ログインしているユーザーの中から自分のアカウントを操作できるのは自分だけと制限をかける.

認可の実装してみる.

①ログインを促す.
ログインしているユーザー⇨全ての操作ができる.
ログインしていないユーザー⇨特定の操作しかできない.
ログインしていないユーザーはどんな操作ができないようにするのがいいのか「編集とか削除など」の自分しか操作できないようにするのが好ましい機能に認可をつける.
ここではログインしている人だけが編集できるようにし、ログインしていないユーザーはログインしてから編集操作してくださいというようにログインしている時としていない時で操作できる範囲を分ける. コントローラに before_actionメソッドを追加する.

 before_action :①logged_in_user, ②only: [:edit, :update]
before_action :①メソッド名,②オプション

意味は②オプションの中のメソッド(アクション)が呼び出された時は、先に①のメソッドを呼び出してという意味.
なのでeditアクションやupdateアクションが呼び出された時は先にlogged_in_userのメソッドを呼び出してという意味.
そしてlogged_in_userメソッドをこのように定義する. 補足rubyの記法でメソッド(アクション)を引数で渡すときはシンボルの形で渡す。今回で言うところの:logged_in_userや:editなど

def logged_in_user
      unless logged_in?
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

logged_in_userメソッドの意味は「ログインしていないならログインして」という意味です.

②ログインしようとしているユーザーが本当に正しいユーザーかチェックする.

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:edit, :update]
  before_action :correct_user,   only: [:edit, :update]

①作成したログインを促すbefore_actionのメソッドの下に新しいbefore_actionのメソッドを定義する.
引数の:correct_userメソッドの中で,

 # 正しいユーザーかどうか確認
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless @user == current_user
    end

current_userで今ログインしているユーザーとデータベースから引っ張ってきた@userが同じじゃなかったらroot_urlにリダイレクトする、同じだったら別の処理を行う.

補足 current_userはログインしていたら使えるメソッド。 ログインしていない状態だとcurrent_userは使えない.

ログイン機能の仕組みの復習

記事の対象者

誰のために記事を作成するのか?⇨rails tutorialを学習中の初学者.
どんな内容の記事か?⇨ログインの仕組みから実際にログイン機能を実装するまでの流れ.
記事の作成者→プログラミング学習歴8ヶ月程度の初心者.

目次

①基本的なログインの仕組み.
②ログイン機能実装手順

基本的なログインの仕組み

ブラウザー(サファリやgoogle chromeなど)にユーザーを特定できる情報(メールアドレスやパスワード)を保存する.
それらの情報を保存する場所をcookieという. つまりブラウザーcookieという場所にユーザーを特定できる情報を保存する.
そのブラウザーのクッキーの中のユーザーに関する情報とサーバーのsessionという場所に保存されているユーザー情報があっているか検証して.
あっている場合⇨ログインする.
あっていない場合⇨ログインしてとブラウザーにレスポンスを返す.

ログイン機能実装手順.

ブラウザーとwebサーバー両方の中にcookieの中の情報(個人を特定できる情報)を入れる=sessionメソッドを使う.

①log_in(user)メソッドの作成し該当するコントローラーのcreateアクション内に記載する app/helper/sessions_helper.rbの中に

def log_in(user)
session[:user_id] = user.id
end 
end 

と記載する。なぜhelper/sessions_helper.rbにlog_inメソッドを定義するかというとコントローラーの中でこのlog_inメソッドを何度も使用できるようにするため.
メソッドの中にメソッドを入れるの可読性を上げるため.

session[:user_id] = user.id

def log_in(user)
session[:user_id] = user.id
end 
end 

この2つはどちらも同じ意味だが下のlog_in(user)の方を使う。理由は使用する際に何をするのかパッと見わかりやすい.

def create 
session[:user_id] = user.id /×何をしているのかパッと見わかりにくい
log_in(user) /○あっログインしようとしているなとパッと見わかりやすいため
end
session[:user_id] = user.id 

↑のsessionメソッドで何が行われるのか?.
cookieを作成しその中にユーザー情報を保存しブラウザーの中に保存するのとwebサーバー側の中にもそのcookie情報を保存する.
仕上げにこのsessionメソッドをsessionコントローラーのcreateアクションの中でlog_inメソッドを呼び出すとログインできるようになる.