0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React + Rails初心者の歩み 〜初級編:超基礎アプリ開発⑤〜

Posted at

はじめに

今回は問題集:初心者編の、
「SessionControllerを作成して、emailとpasswordでログインできるAPIを実装」
を進めていきます。

Rails

まずは、セッションコントローラーを作成します。
この「セッション」はログイン状態の管理・判定を行う機能になります。

rails g controller Sessions

できたコントローラーに記述していきます。

# app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def create
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      session[:user_id] = user.id
      render json: {logged_in: true,user: user}
    else
      render json: {logged_in: false,errors: ['Invalid credentials']},status: 401
    end
  end

  def destroy
    session.delete(:user_id)
    render json: {logged_out:true}
  end

  def auth_check
    if session[:user_id]
      user = User.find(session[:user_id])
      render json: {logged_in: true, user: user}
    else
      render json: {logged_in: false}
    end
  end
end

1つ1つ解説していきます。

create

createはフロント(React)側から送られてくるメールアドレス・パスワードによるログインリクエストに対応する処理になります。

def create
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      session[:user_id] = user.id
      render json: {logged_in: true,user: user}
    else
      render json: {logged_in: false,errors: ['Invalid credentials']},status: 401
    end
end

user = User.find_by(email: params[:email])

送られてきたメールアドレス(params[:email])で、
User.find_by()を使ってデータベース内で一致するメールアドレスを探しています。
find_by内のemail:はデータベース内のメールアドレスのカラム(email:)を指定しています。

if user&.authenticate(params[:password])

パスワードを照合する記述です。
「user&.」は「ユーザーが見つかっていれば(nilでなければ)」という意味になります。
「authenticate()」は、has_secure_password(Userモデルで宣言済み)によって提供されるメソッドで、ハッシュ化されたパスワードと照合して認証します。
パスワードが正しければそのユーザーオブジェクトを返し、間違っていればfalseを返します。

session[:user_id] = user.id

ログインに成功した場合、Railsのセッションに「user_id」を保存します。
Userコントローラーを追加した時にも使いましたね。
これにより、その後のリクエストでもこのユーザーがログイン済みであることをRails側で判断できます(クッキーに保存される)。

render json: {logged_in: true,user: user}

JSON形式でログイン成功をフロントエンドに返します。
Userでは「status: 'created'」でしたが、
ログインの時は「logged_in: true」になります。

user情報も返していますが、必要な情報だけを返すように制限するのがセキュリティ的にはおすすめ
(例:Serializerやonly: [:id, :email]などを使う)。
By GPTえもん

render json: {logged_in: false,errors: ['Invalid credentials']},status: 401

ユーザーが見つからない、またはパスワードが間違っている場合に実行されます。
「logged_in: false」とエラーメッセージを返しています。
「status: 401」はHTTPステータスコードで「Unauthorized(認証失敗)」を意味します。

destroy

destroyはログアウト機能になります。
今回はログアウト機能の実装はしない為、React側では特に実装しませんが、
この先実装予定なのでRails側では作成しておきます。

def destroy
    session.delete(:user_id)
    render json: {logged_out:true}
end

session.delete(:user_id)

これはセッション(ログイン情報)から「:user_id」を削除する処理です。
具体的には、サーバー側に保存されているログイン中のユーザーIDを削除することで、「ログアウト状態」にします。
ユーザーがログイン中かどうかは「session[:user_id]」によって判定されているので、これを削除すればログアウトになります。

render json: { logged_out: true }

JSON形式でログアウト成功をフロントエンドに返します。
「logged_out: true」という情報を送ることで、React側で状態を更新したり、ログインページにリダイレクトしたりするのに使えます。

auth_check

auth_checkは現在ログインしているかどうかを確認するための処理になります。

def auth_check
    if session[:user_id]
      user = User.find(session[:user_id])
      render json: {logged_in: true, user: user}
    else
      render json: {logged_in: false}
    end
end

if session[:user_id]

ユーザーがログイン中かどうかを判断しています。
createでuser_idを保存したやつですね。
「session[:user_id]」に値が入っていれば、ログイン済みになります。

user = User.find(session[:user_id])

user_idを使ってusersテーブルからユーザー情報を探す処理です。
これによってログイン中のユーザー情報を取得しています。
ユーザー名を表示したりする為ですね。

render json: {logged_in: true, user: user}

ログインしている場合は、「logged_in: true」を返して、
ユーザー情報も一緒に返しています。
これを使ってフロントエンド側では誰がログインしているかを判断できます。

render json: {logged_in: false}

ログインしていない場合は「logged_in: false」を返します。

routes

最後にroutesを記述していきます。

# config/routes.rb
post "/login" => "sessions#create"
delete "/logout" => "sessions#destroy"
get "/auth_check" => "sessions#auth_check"

以上がRails側の処理になります!
ではReactに行ってみよう!

React

ではLoginForm.jsxというコンポーネントを作成して、処理を書いていきます。

function LoginForm() {
  const [email,setEmail] = useState('')
  const [password,setPassword] = useState('')
  const [message,setMessage] = useState('')

  const handleLogin = async(e)=> {
    e.preventDefault();
    try {
      const res = await axios.post('http://127.0.0.1:3000/login',
        {
          email,password
        },
        {
          headers: {
            "Content-Type": "application/json"
          },
          withCredentials: true
        }
      )
      setMessage('ログイン成功!');
    }catch(err){
      setMessage('ログイン失敗');
    }
  }
  return (
    <>
      <form onSubmit={handleLogin}>
        <input
            type="email"
            name="email"
            value={email}
            onChange={e=>setEmail(e.target.value)}
            placeholder="email"
        />
        <input
            type="password"
            name="password"
            value={password}
            onChange={e=>setPassword(e.target.value)}
            placeholder="password"
        />
        <button className="btn" type="submit">ログイン</button>
        <p>{message}</p>
      </form>
    </>
  )
}

export default LoginForm

1つ1つ解説していきます。

stateの定義

今回は「メールアドレス」「パスワード」「エラーメッセージ」のstateを定義しています。

e.preventDefault()

フォーム標準の再読み込み動作を防ぎます。

handleLogin

JSONのやりとりについては省略。

const res = await axios.post('http://127.0.0.1:3000/login',

データを送信しますので、「get」ではなく「post」。
送信先は「http://127.0.0.1:3000/login 」に指定しています。

email,password

送信するデータです。

出力

return (
    <>
      <form onSubmit={handleLogin}>
        <input
            type="email"
            name="email"
            value={email}
            onChange={e=>setEmail(e.target.value)}
            placeholder="email"
        />
        <input
            type="password"
            name="password"
            value={password}
            onChange={e=>setPassword(e.target.value)}
            placeholder="password"
        />
        <button className="btn" type="submit">ログイン</button>
        <p>{message}</p>
      </form>
    </>
)

一般的なログインみたいな感じにはこの時点でなっていないですが、
基本的なユーザー登録・ログインの処理自体はできています。
以上で完了!!!!

まとめ

前回のユーザー登録から今回のログイン処理については、
しっかりと読み込んで処理の記述になれていきたい所存でございます。
めちゃくちゃよく使う基本的な処理ですもんね。
読み込んで手を動かすのみ!

俺の手よ動けぇぇぇぇぇぇぇぇ・・・・!

ではまた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?