仕様書
- ユーザーのログイン機能
- ログインした後の状態管理
- ログアウト機能
ログインページのview作成
ルーティングの設定
get "login" => "users#login_form"
コントローラの設定
def login_form
end
DBにパスワードカラムの追加
マイグレーションファイルの設定
rails g migration add_password_to_users
コマンドからmigrationファイルを作成し、マイグレーションファイルを下記に編集。
class AddPasswordToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password, :string
end
end
バリデーションの設定
class User < ApplicationRecord
validates :name, {presence: true}
validates :email, {presence: true, uniqueness: true}
# passwordカラムにバリデーションを設定してください
validates :password, {presence: true}
end
passwordに空欄だとはじくバリデーションをmodelのuser.rbに記述。
ログインフォームの作成
ルーティングの設定
post "login" => "users#login"
DBに変更を与えるのでpostで設定
アクションの設定
def login
end
中身は空だがusers#loginに対応するアクションを設定。
viewにおけるフォームの設定
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<!-- name属性を追加してください -->
<input name ="email">
<p>パスワード</p>
<!-- name属性を追加してください -->
<input type="password" name ="password">
<input type="submit" value="ログイン">
<!-- form_tag用のendを追加してください -->
<% end %>
ルーティングはroutes.rbでは最初に/が無いが他のファイルで設定する場合は/で始める。ルートは基本的にはroutes.rbで確認すると分かる。
このviewで/loginに値を送信するフォームを作成。inputにnameで値を設定。
ユーザーを特定する
ログインしたユーザーを特定し、そのユーザーのページを表示するための機能。
def login
@user = User.find_by(email: params[:email], password: params[:password])
if @user
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else
render("users/login_form")
end
end
User.find_by(email: params[:email], password: params[:password])でpassword、email両方一致した場合のみ引っ張ってくる。
redirect_toはURLを送って問い合わせるため基本はroutes.rbのURLで良い。ただrenderはviewの相対パスに直接問い合わせを行う。users/login_formもviewをhomeにした時の相対パス。なので最初に/がない。
特定したユーザーが登録済みユーザーじゃなかった場合
def login
@user = User.find_by(email: params[:email], password: params[:password])
if @user
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else
@error_message = "メールアドレスまたはパスワードが間違っています"
@email = params[:email]
@password = params[:password]
render("users/login_form")
end
end
@userにもしなにも値が無かった場合、elseでeroorメッセージを流し、renderでlogin_formに流す。
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email" value="<%= @email %>">
<p>パスワード</p>
<input type="password" name="<%= @password %>">
<input type="submit" value="ログイン">
<% end %>
初期値に前に登録した値を持ってくる。
ログインしたユーザー情報の保持(状態管理)
def login
@user = User.find_by(email: params[:email], password: params[:password])
if @user
session[:user_id] = @user.id
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else
@error_message = "メールアドレスまたはパスワードが間違っています"
@email = params[:email]
@password = params[:password]
render("users/login_form")
end
end
sessionにuser_idを入れる。viewに
<% if session[:user_id] %>
<li>
現在ログインしているユーザーのid: <%= session[:user_id] %>
</li>
<% end %>
session[:user_id]は@つけなくてもそのままviewに表示できる。
ログアウト機能
ログアウトのメソッド
ログアウトはセッションにnilを代入することで行う。この時ルーティングはgetではなく、postを使う。
- get・・・データベースを変更しない場合
- post・・・データベース、sessionの値を変更する場合
session[:user_id] = nil
controllerから権限の必要なページを限定する
before_actionで制限
before_action: メソッド名,{only:[:アクション名,:アクション名]}
アクセス制限
非ログインユーザーに対してのアクセス制限
ログインしていないユーザーがURLを直接叩いても見れないようにアクセス制限をかけよう。application_controllerにforbid_login_userメソッドというログインを禁じるものを作り、各controllerに継承させる。
ensure_correct_userメソッドというログインユーザーと編集しようとしているユーザーのidが一致しない場合にアクセスを拒否するメソッドを作成し、before_actionで複数のアクションに用いる。
def ensure_correct_user
if @current_user.id != params[:id].to_i
flash[:notice] = "権限がありません"
redirect_to("/posts/index")
end
end
params[:id]で取得できる値は文字列のため.to_iメソッドを使って数字に変換する。
リンクなどの非表示
<% if @user.id == @current_user.id %>
<%= link_to("編集", "/users/#{@user.id}/edit") %>
<% end %>
上記でuser.idと現在ログインしているuser.idが違うと表示されないようにする。
他のユーザーの情報を編集できないように制限をかける
あとで追記