RailsTutorial8章

積読

全体像

f:id:shiness:20210113175702p:plain

メソッドについて

    user = User.find_by(email: params[:session][:email].downcase)
    if @user && @user.authenticate(params[:session][:password])

if@userがないと一行目でnilが返って来たときにnilに対してauthenticate を使うことになってerrorが出ることを防ぐ目的がある。

renderとredirect_toの違い

参考 【Rails】renderとredirect_toの違いと使い分け - Qiita

DB問い合わせ削減の書き方

  def current_user
    if session[:user_id]
      @current_user ||= User.find_by(id: session[:user_id])
    end
  end

if session[:user_id]と予め書いておくことでfind_byの試行回数を減らせる。 DB問い合わせ数削減のため。

@current_userがnilまたはfalseだったら右を実行する。 これもDBへの問い合わせ削減。インスタンス変数の寿命の長さを利用したコ−ド。

なぜsessions_controllerではインスタンス変数ではなくローカル変数を使うのか

Ruby - railsチュートリアル 8章 createアクション内の変数についての質問|teratail

def login(user)の理由について

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

log_in(user)とuserを引数にとらないようにするため 以下のように書けるが

session[:user_id] = @user.id

一般的に Helper は参照透過性のある関数として書かれることが良いとされるため 別の Controller からも log_in ヘルパーを利用したくなった時に、「log_in ヘルパーを呼ぶ前に予め @user というインスタンス変数にログインしたいユーザーのインスタンスをセットしておくこと」 という複雑なルールを強いられることになります。それよりも、単純に log_in のシグネチャーとして「引数で渡されたユーザーでログインする」という挙動にしておいた方がシンプルなので設計として 落ち着きやすいわけです。

application_helperとapplication_controllerに書くときの違いについて

application_helper viewをDRYにするためのもの

application_controller 共通のメソッドをまとめるためのもの

session_helper

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

  def current_user
    if session[:user_id]
      @current_user ||= User.find_by(id: session[:user_id])
    end
  end
  
  def logged_in?
    !current_user.nil?
  end

  def log_out
    session.delete(:user_id)
    @current_user = nil
  end
end

sessions_controller.rb

class SessionsController < ApplicationController
  
  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if @user && @user.authenticate(params[:session][:password])
      log_in user
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination' # 本当は正しくない
      render 'new'
    end
  end

  def destroy
    log_out
    redirect_to root_url
  end
end

application_controller

class ApplicationController < ActionController::Base
  include SessionsHelper
end

users_controller

class UsersController < ApplicationController
  
  def show
    @user=User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      log_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end