17. 헬퍼를 이해하고 로그아웃 기능 구현

2020. 6. 30. 16:17Rails 5 on aws c9

17. 헬퍼를 이해하고 로그아웃 기능 구현

헬퍼는 뷰에서 코드를 조금더 간단하게 쓸 수 있는 방법이다

레일즈에서 기본으로 제공하는 form_tag 나 link_to 헬퍼를 사용했다.

이걸 직접 구현할수도 있다.

헬퍼들은 app/helpers에 모여있다

컨트롤러별로 헬퍼가 생성된걸 볼 수 있다.

로그인 로그아웃에 관련된 기능을 sessions_helper.rb에 작성해보자.

우선 application_controller에 헬퍼를 사용할 수 있게 include를 시켜야 한다.

여기에 include하면 모든 곳에서 쓸 수 있다고 생각하면 된다.

그다음 SessionsHelper에 돌아가서,

우리가 지난번에 로그인을 처리했던 방식은, 다음과 같았다.

class SessionsController < ApplicationController
            ...

            #세션이라는 키워드에 해시처럼 관리
      #다음부터 세션하고 유저아이디로 불러오면, 로그인한 사용자의 아이디를 불러올 수 있게 된다. 
      #어느 액션에서나 볼 수 있다.
      #세션에 user_id가 있으면 전부 로그인된 사용자로 처리
      **session[:user_id] = user.id**

            ...
end

이걸 함수로 짜보자.

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

그럼 다시 코드로 돌아가서 session[:user_id] = user.id 대신에 log_in(user)를 써준다.

class SessionsController < ApplicationController
  def new
  end

  def create
    #유저를 이메일로 찾아서 있으면 user가 ture취급
    #그리고 비밀번호를 해싱해서 일치하나 확인 
    #둘다 참이면 로그인
    user = User.find_by(email: params[:email])
    if user && user.authenticate(params[:password])
      #세션이라는 키워드에 해시처럼 관리
      #다음부터 세션하고 유저아이디로 불러오면, 로그인한 사용자의 아이디를 불러올 수 있게 된다. 
      #어느 액션에서나 볼 수 있다.
      #세션에 user_id가 있으면 전부 로그인된 사용자로 처리
      ***log_in(user)***
      redirect_to '/'
    else
      #sessions/new.html.erb에서 맨 위에 소스코드 추가필요 <%= flash[:alert]%>
      flash[:alert] = 'Invalid email/password combination'
      #sessions/new의 prefix가 new_session 이므로
      redirect_to new_session_path
    end
  end
end

이렇게만 봤을 때 세션핼퍼를 쓴게 장점으로 보이질 않는다

그럼 좀더 복잡한 기능을 짜보자

뷰로 가보자.

application.html.erb로 가면

임시로 작성했던 코드가 보인다.

세션이 존재할때 사용자의 정보에서 이름을 호출하는것

뷰에서 모델을 호출하는 살짝 문제있는 코드를 고쳐보자

현재 로그인한 유저를 받아오는 헬퍼를 이후에 current_user로 만들것이다.

<!DOCTYPE html>
<html>
  <head>
    <title>HelloWorld</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div id="global-header">
      <div class="container">
        <div class="logo">My Profile</div>
        <ul class="menu">
          <a href="/">
            <li class="item">Hello World</li>
          </a>
          <!--link_to 헬퍼를 이용 해보자-->
          <!--<a href="/contacts/new">-->
          <%= link_to new_contact_path do %>
            <li class="item">Contact</li>
          <!--</a>-->
          <% end %>
          <%= link_to new_user_path do %>
            <li class="item">Sign up</li>
          <% end %>
          <% if session[:user_id] %>
            ***<li class="item"><%= current_user.name %></li>***
          <% end %>
        </ul>
      </div>
    </div>

    <%= yield %>
  </body>
</html>

아직은 동작하지 않을것이다. 헬퍼에서 기능을 구현하자.

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

    # @current_user 는 인스턴스 변수로 조금 더 오래남는 변수다/
    # 위의 코드와 같이 @current_user = User.find_by(id: sessions[:user_id]) 한줋로 퉁쳐도 되지만
    # 메뉴바를 보여줄 때 마다(매 액션마다) db를 조회하면 성능이 느려지므로 방지한다.
    def current_user
        if @current_user.nil?
            @current_user = User.find_by(id: session[:user_id])
        else
            @current_user = @current_user
        end
        #한줄로 표현하면
        #@current_user = @current_user || User.find_by(id: session[:user_id])
        #or
        #@current_user ||= User.find_by(id: session[:user_id])
    end
end 

또, application.html.erb에서 <% if session[:user_id] %> 부분을 의미가 드러나게 바꿔보자.

<!DOCTYPE html>
<html>
  <head>
    <title>HelloWorld</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div id="global-header">
      <div class="container">
        <div class="logo">My Profile</div>
        <ul class="menu">
          <a href="/">
            <li class="item">Hello World</li>
          </a>
          <!--link_to 헬퍼를 이용 해보자-->
          <!--<a href="/contacts/new">-->
          <%= link_to new_contact_path do %>
            <li class="item">Contact</li>
          <!--</a>-->
          <% end %>
          <%= link_to new_user_path do %>
            <li class="item">Sign up</li>
          <% end %>
          ***<!-- if session[:user_id] -->**
          **<% if user_signed_in? %>***
            <li class="item"><%= current_user.name %></li>
          <% end %>
        </ul>
      </div>
    </div>

    <%= yield %>
  </body>
</html>

헬퍼에 user_signed_in? 추가

하는김에 로그아웃 기능 추가.

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

    # @current_user 는 인스턴스 변수로 조금 더 오래남는 변수다/
    # 위의 코드와 같이 @current_user = User.find_by(id: sessions[:user_id]) 한줋로 퉁쳐도 되지만
    # 메뉴바를 보여줄 때 마다(매 액션마다) db를 조회하면 성능이 느려지므로 방지한다.
    def current_user
        if @current_user.nil?
            @current_user = User.find_by(id: session[:user_id])
        else
            @current_user = @current_user
        end
        #한줄로 표현하면
        #@current_user = @current_user || User.find_by(id: session[:user_id])
        #or
        #@current_user ||= User.find_by(id: session[:user_id])
    end

    def user_signed_in?
        !current_user.nil?
    end

    def log_out
        #session[:user_id] = nil 해도 됨
        session.delete(:user_id)
        @current_user = nil
    end

end

이제 뷰에서 컨트롤러의 로그아웃 액션을 호출할 수 있게 컨트롤러를 수정해주자.

class SessionsController < ApplicationController
  def new
  end

  def create
    #유저를 이메일로 찾아서 있으면 user가 ture취급
    #그리고 비밀번호를 해싱해서 일치하나 확인 
    #둘다 참이면 로그인
    user = User.find_by(email: params[:email])
    if user && user.authenticate(params[:password])
      #세션이라는 키워드에 해시처럼 관리
      #다음부터 세션하고 유저아이디로 불러오면, 로그인한 사용자의 아이디를 불러올 수 있게 된다. 
      #어느 액션에서나 볼 수 있다.
      #세션에 user_id가 있으면 전부 로그인된 사용자로 처리
      log_in(user)
      redirect_to '/'
    else
      #sessions/new.html.erb에서 맨 위에 소스코드 추가필요 <%= flash[:alert]%>
      flash[:alert] = 'Invalid email/password combination'
      #sessions/new의 prefix가 new_session 이므로
      redirect_to new_session_path
    end
  end

  def destroy
    log_out
    redirect_to '/'
  end
end

이제 뷰에 로그아웃 기능을 붙여보자

<!DOCTYPE html>
<html>
  <head>
    <title>HelloWorld</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div id="global-header">
      <div class="container">
        <div class="logo">My Profile</div>
        <ul class="menu">
          <a href="/">
            <li class="item">Home</li>
          </a>
          <!--link_to 헬퍼를 이용 해보자-->
          <!--<a href="/contacts/new">-->
          <%= link_to new_contact_path do %>
            <li class="item">Contact</li>
          <!--</a>-->
          <% end %>
          <% if user_signed_in? %>
            <li class="item"><%= current_user.name %></li>
            <!-- rake routes하면 session DELETE /sessions/:id(.:format) sessions#destroy -->
            <li class="item"><%= link_to 'Sign out', session_path(current_user), method: 'delete' %></li>
          <% else %>
          <% end %>

          <%= link_to new_user_path do %>
            <li class="item">Sign up</li>
          <% end %>
          <!-- if session[:user_id] -->
          <% if user_signed_in? %>

          <% end %>
        </ul>
      </div>
    </div>

    <%= yield %>
  </body>
</html>

새로고침하면 이렇게 sign out 이 생긴다.

누르면 이렇게 로그아웃이 된걸 볼 수 있다.

마지막으로 메뉴들 정리한 코드들

<!DOCTYPE html>
<html>
  <head>
    <title>HelloWorld</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div id="global-header">
      <div class="container">
        <div class="logo">My Profile</div>
        <ul class="menu">
          <a href="/">
            <li class="item">Home</li>
          </a>
          <!--link_to 헬퍼를 이용 해보자-->
          <!--<a href="/contacts/new">-->
          <%= link_to new_contact_path do %>
            <li class="item">Contact</li>
          <!--</a>-->
          <% end %>
          <% if user_signed_in? %>
            <li class="item"><%= current_user.name %></li>
            <!-- rake routes하면 session DELETE /sessions/:id(.:format) sessions#destroy -->
            <li class="item"><%= link_to 'Sign out', session_path(current_user), method: 'delete' %></li>
          <% else %>
            <li class="item"><%= link_to 'Sign in', new_session_path %></li>
            <li class="item"><%= link_to 'Sign up', new_user_path %></li>
          <% end %>
        </ul>
      </div>
    </div>

    <%= yield %>
  </body>
</html>

다음강에서는 관리자만 contact list를 볼 수 있게 만들어보겠다.