\ プログラミング学習奮闘記録 /

Progate学習メモ Ruby on Rails5【SNSを作る⑥〜ログイン機能を作る〜】

目次

ログインとは

ログインとは、サイトを操作しているユーザーが誰であるかが判別できる状態のこと

ログインしていることにより、操作しているユーザーに合わせて、同じURLでもユーザーごとに表示を変えることができる

↓やること

  • ログイン機能
  • ログアウト機能
  • ログインしているユーザー名の表示
  • ログインしているかどうかでアクセス制限をする
  • ログインしているユーザー情報のみ編集できるようにする

ログイン機能

ログインの流れ

  1. ログインページからメールアドレスやパスワードなどの情報をRailsに送信
  2. 送信された情報を元に操作しているユーザーを特定
  3. ログイン状態にする

ログインページを作成する

ルーティング、アクション、ビューを追加する

《ルーティング》

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

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次