ログインとは
ログインとは、サイトを操作しているユーザーが誰であるかが判別できる状態のこと
ログインしていることにより、操作しているユーザーに合わせて、同じURLでもユーザーごとに表示を変えることができる
↓やること
- ログイン機能
- ログアウト機能
- ログインしているユーザー名の表示
- ログインしているかどうかでアクセス制限をする
- ログインしているユーザー情報のみ編集できるようにする
ログイン機能
ログインの流れ
- ログインページからメールアドレスやパスワードなどの情報をRailsに送信
- 送信された情報を元に操作しているユーザーを特定
- ログイン状態にする
ログインページを作成する
ルーティング、アクション、ビューを追加する
《ルーティング》
get “login” => “users#login_form” ← ログインページのルーティング
《コントローラ》
def login_form
end
《ビュー》パスワード入力フォームを追加する
<p>パスワード</p>
<input type=”password”> ← これでパスワード用のフォームになる
パスワードカラムを作成する
「rails g migration」を用いて、add_password_to_usersというファイル名のマイグレーションファイルを作成する。
《ターミナル》
$ rails g migration add_password_users ← カラムを追加して
$ rails db:migrate ← マイグレーションファイルの中身を書いたら実行する
《マイグレーションファイルの中身》
def change
add_column :users, :password, :string → テーブル名、カラム名、データ型
end
バリデーションをかける
ユーザーの情報には必ずpasswordの値が存在してほしいので、passwordカラムにもバリデーションをかける
《model/user.rb》
validates :password, {presence: true}
- 「存在するかどうか」のバリデーションは「presence」を使う
- リスト
フォームの値を送信できるようにする
フォームから送信された値を受け取るために、ルーティングとアクションを追加する
《ルーティング》
post “login” => “users#login” ← フォームの値を送信するルーティング
対応するアクションはusersコントローラのloginアクションとなるようにする。
《コントローラ》
def login
ログイン処理
end
《ビュー》 ← form_tagの送信先を指定する
<%= form_tag(“/login”) do %>
<p>ユーザー名</p>
<input name=”name”>
<p>パスワード</p>
<input type=”password” name=”password”>
<% end %>
ログイン機能の流れ
ユーザーを特定してログインする
送信されたメールアドレスとパスワードでユーザーを特定する
def login
@user = User.find_by( email: params[:email], →入力されたメールアドレスとパスワードを受け取る
password: params[:password] )
if @user ← userが存在しているかどうかで表示を変える
flash[:notice] = “ログインしました” → userが存在していた場合の処理
redirect_to(“/posts/index”) 「ログインしました」と表示されて、投稿一覧へ
else
render(“/users/login_form”) →userが存在していなかった場合の処理。
end ログインページを再表示する
end
- フォームに入力されたメールアドレスとパスワードはparams[:email]とparams[:password]で受け取れる
- usersテーブルから入力された値に一致するユーザーを取得し、変数@userに代入する
- find_byメソッドは引数をコンマ( , )で区切ることで複数の条件からデータベースを検索することができる
ユーザーが存在しない場合の処理
ユーザーが存在しない場合、再度ログインページを表示したが、その際に、以下も表示するようにする。
- エラーメッセージ
- フォームに初期値を入れる
エラーメッセージの表示
《コントローラ》
def login
@user = User.find_by( email: params[:email],
password: params[:password] )
if @user
flash[:notice] = “ログインしました”
redirect_to(“/posts/index”)
else
@error_message = “メールアドレスまたはパスワードが間違っています”
render(“/users/login_form”)
end
end
《ビュー》
<% if @error_message %>
<div class=”error_message”>
<%= @error_message%> → エラーメッセージの表示
</div>
<% end %>
- 今回のエラーメッセージはバリデーションのエラーメッセージとは異なり、「find_byメソッドで検索したが存在しなかった」という結果を伝えるためのものなので、自作する必要がある
初期値の表示
《コントローラ》
if @user
flash[:notice] = “ログインしました”
redirect_to(“/posts/index”)
else
@email = params[:email]
@password = params[:password]
@error_message = “メールアドレスまたはパスワードが間違っています”
render(“/users/login_form”)
end
end
《ビュー》
<%= form_tag(“/login”) do %>
<p>ユーザー名</p>
<input name=”email” value=”<%= @email %>”>
<p>パスワード</p>
<input type=”password” name=”password” value=”<%= @password %>”>
<% end %>
- 変数@emailと@passwordを定義し、それぞれにparams[:email]とparams[:password]の値を代入し、フォームに入力した値が初期値となるようにする
- また、変数に代入した初期値を表示するためにフォームにvalue属性を追加する
ログインした後、ユーザー情報を処理する 変数session
ページを移動してもユーザー情報を保持し続けるために、sessionという特殊な変数を使う
sessionに代入された値は、ブラウザ(InternetExplorer, GoogleChrome等)に保存される
sessionに値を代入すると、ブラウザはそれ以降のアクセスでsessionの値をRailsに送信する
《コントローラ》
if @user
session[:user_id] = @user.id
- 値を代入するときは、user_idをキーとし、値を代入する → session[:キー名]=値
- @userが存在する場合に変数sessionに@user.idを代入することで、特定したログインユーザーの情報が保持され続ける
ログイン中のユーザーidを表示する
session[:user_id]に代入した値がページを移動しても保持され続けることを確認するために、ログインしたユーザーのidをヘッダーに表示する
《application.html.rb》 ←ここに入力することで、ページを移動しても表示され続ける
<li>
現在ログインしているユーザーのid:
<%= session[:user_id] %>
</li>
- session[:user_id]とすることで、ブラウザから送信された変数sessionの値を取得することができる
ログアウト機能
ログイン時は変数セッションに値を代入することで、「ログイン中」の状態が保持された。
ログアウトの場合は、変数セッションの値を削除してしまう。
→ 「ログイン状態でなくする」にはsession[:user_id]の値を空にする
《コントローラ》
def logout
session[:user_id] = nil
end
- session[:user_id]にnilを代入することで、session[:user_id]の値を空にできる
ログアウトアクションを作成する
《ルーティング》
post “logout” => “users#logout”
logoutのルーティングはloginと同様に、「get」ではなく「post」
《コントローラ》
def logout
session[:user_id] = nil
flash[:notice] = “ログアウトしました”
redirect_to(“/login”)
end
getとpostの使い分け
get:
・データベースを変更しない場合
post:
・データベースを変更する場合
・sessionを用いる場合
ログイン時とログアウト時でヘッダーの表示内容を切り替える
《application.html.rb》
<% if session[:user/id] %>
<li>
<%= session[user_id] %> ←ログイン状態の時に表示する内容
</li>
<% else %>
<li>
<%= link_to(“TweetAppfとは”,”/about”) %> ← ログアウト状態の時に表示する内容
</li>
<% end %>
- ログイン状態の時に表示する内容:session[:user_id]、投稿一覧、新規投稿、ログアウト
- ログアウト状態の時に表示する内容:TweetAppとは、ログイン
<% if session[:user_id] %>
現在ログインしているユーザーのid: <%= session[:user_id] %>
<%= link_to(“投稿一覧”, “/posts/index”) %>
<%= link_to(“新規投稿”, “/posts/new”) %>
<%= link_to(“ユーザー一覧”, “/users/index”) %>
<%=link_to(“ログアウト”,”/logout”,{method:”post”})%>
<% else %>
<%= link_to(“TweetAppとは”, “/about”) %>
<%= link_to(“新規登録”, “/signup”) %>
<%= link_to(“ログイン”, “/login”) %>
<% end %>
ユーザー登録時のログイン
《new.html.rb》
ユーザー登録フォームにパスワード入力欄を追加する
<p>パスワード</p>
<input name=”password” type=”password” value=”<%= @user.password %>”>
《コントローラ》
createアクションのnewメソッドの引数としてpasswordを追加することで、
ユーザー登録時にpasswordカラムの値が設定されるようにする。
def create
@user = User.new(
name: params[:name],
email: params[:email],
image_name: “default_user.jpg”,
password: params[:password]
)
- リスト
- リスト
ユーザー登録時にログイン状態にする
《コントローラ》
usersコントローラのcreateアクション内で作成したユーザーのidをsession[:user_id]に代入する
if @user.save
session[:user_id] = @user.id
flash[:notice] = “ユーザー登録が完了しました”
redirect_to(“/users/#{@user.id}”)
else
render(“users/new”)
end
ログインしているユーザー名を表示する
session[:user_id]の値をもとに、ログイン中のユーザーの情報をデータベースから取得する
《application.html.rb》
<% current_user = User.find_by(id: session[:user_id]) %>
ログイン中のユーザー情報(Userインスタンス) ログイン中のユーザーid
find_byメソッドを用いてusersテーブルからidカラムの値がsession[:user_id]と等しいユーザーを取得し、変数に代入
<li>
<%= link_to(current_user.name,”/users/#{current_user.id}”)%>
</li> ログイン中のユーザー名
表示するユーザー名はそのユーザーの詳細ページへのリンクする
各コントローラの全アクションで共通する処理がある場合 before_action
各コントローラの全アクションで共通する処理がある場合には、before_actionを使うと便利
before_actionを用いることで、アクションが呼び出される際に必ずbefore_actionの処理が実行される
これにより、全アクションで共通する処理を1箇所にまとめることができる
applicationコントローラ
全てのコントローラで共通する処理はapplicationコントローラにまとめることができる。
《applicationコントローラ》
ログイン中のユーザーを取得するset_current_userメソッドを定義し、before_actionに指定する
before_action :set_current_user
中略
def set_current_user
@current_user = User.find_by(id: session[:user_id])
end
- これで、全コントローラの全アクションで@current_userを定義することができる
- @変数で定義した変数は同じクラスの異なるメソッド間で共通して使用することが可能
ログインしていない場合のアクセス制限
ログインしていない場合でも、左図のようにURLを直接入力するとアクセスできてしまう。
@current_userがいない場合にはログインページにリダイレクトするようにする。
《applicationコントローラ》
def authenticate_user ←「ユーザー認証する」と言う意味
if @current_user == nil
flash[:notice] = “ログインが必要です”
redirect_to(“/login”)
end
before_actionを特定のアクションのみで実行する
onlyを用いて各コントローラでbefore_actionを使うことで、指定したアクションでのみそのメソッドを実行することができる。
《usersコントローラ》
before_action :authenticate_user, {only:[:update, :edit]}
- onlyを用いて、適応したいアクションを指定する
- その際には[ ]を用いて配列型式にする
ログインしているユーザーがアクセスできないページ
applicationコントローラ内に「ログインユーザーを禁止する」という意味の、forbid_login_userメソッドを作成する
《applicationコントローラ》
def forbid_login_user
if current_user
flash[:notice] = “すでにログインしています”
redirect_to(“/posts/index”)
end
end
- ログインユーザーが存在する場合、投稿一覧ページにリダイレクトする
- メソッドの実行にはbefore_actionを用い、onlyで適用したいアクションを指定する
ユーザー編集を制限する
詳細ページのユーザーと、ログインしているユーザーが一致する時だけ編集リンクを表示する
編集ページのリンクを非表示にする
《users/show html.rb》
<% if @user.id == @current_user.id%> ← ログインしているユーザとIDが等しい場合
<%= link_to(“編集”/users/#{user.id}/edit)%>
<% end %>
アクションでも編集ページのリンクを制限する
usersコントローラのeditアクションおよびupdateアクションに制限をかける。
「正しいユーザーかを確かめる」という意味のensure_correct_userメソッドを用意し、ログイン中のユーザーのidと編集したいユーザーのidが等しいか判定する。
《users_controller.rb》
before_action :ensure_correct_user,{only:[:edit, :update]}
def ensure_correct_user
if ログイン中のユーザーとIDが等しくない場合
flash[:notice] = “権限がありません”
redirect_to(“/posts/index”)
end
end
to_iメソッド
ログイン中のユーザーのidは@current_user.idに、編集したいユーザーのidはparams[:id]にそれぞれ代入されている。
しかし、params[:id]で取得できる値は文字列であり、数値である@current_user.idと比較してもfalseとなる。
to_iメソッドを用いると、文字列を数値に変換することができる。
to_iメソッドでparams[:id]を数値に変換し、@current_user.idと比較する。
《users_controller.rb》
before_action :ensure_correct_user,{only:[:edit, :update]}
def ensure_correct_user
if @current_user.id != params[:id].to_i ← 文字列を数字に変換している
flash[:notice] = “権限がありません”
redirect_to(“/posts/index”)
end
end
コメント