LoginSignup
suzu_ryuya
@suzu_ryuya (suzu ryu)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Railsアプリで、ログイン状態により表示する項目を変更したい

解決したいこと

現在、Ruby on RailsでTodoアプリを作成しています。ログイン機能を実装しているのですが、ログインしている場合としていない場合で、ヘッダーの表示を以下のように変更するよう実装したいです。
・ログインしている時 =>トップページ、タスク一覧、ログアウト
・ログインしていない時 =>トップページ、新規登録、ログイン
しかし、ログインしても表示が変わらないので、どこを修正したら良いかを質問させていただきました。

実装したこと

Sessionを利用して、ユーザーの判別を行いました。実装したコードとディレクトリの関係を以下に挙げます。
app/controllers/sessions_controller.rb
app/controllers/sessions_helper.rb
app/controllers/users_controller.rb
app/views/layouts/application.html.erb
config/routes.rb
例)

該当するソースコード

app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def new
  end

  def create
    #DBからユーザーを取り出す。
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      #パスワードが登録されたユーザー情報と一致したら、セッションにユーザー情報を登録する。
      log_in user
      redirect_to '/'
    else
      flash[:alert] = 'Invalid email/password combination'
      render 'new'
    end

  end

  def destroy
    log_out
    flash[:notice] = "Logged out!"     #追加が成功した際に、flashメッセージを表示する。
    redirect_to '/'
  end
end

ヘッダーの部分だけ掲載します。

app/views/layouts/application.html.erb
<!--ヘッダー-->
  <header>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand"><%= link_to("Todoアプリ","/")%></a>
        <div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
          <div class="navbar-nav">
            <% if logged_in? %>
            <a class="nav-link"><%= link_to "タスク一覧", tasks_path %></a>
            <a class="nav-link"><%= link_to "ログアウト", logout_path %></a>
            <% else %>
            <a class="nav-link"><%= link_to "新規登録", new_user_path %></a>
            <a class="nav-link"><%= link_to "ログイン", login_path %></a>
            <% end %>
          </div>
        </div>
      </div>
    </nav>

  </header>
config/routes.rb
Rails.application.routes.draw do
  get 'sessions/new'
  get '/' => "home#top" #トップページのルーティング home:コントローラー名 top:アクション名
  get 'login' => 'sessions#new'         #新しいセッションのページ(ログイン)
  post 'login' => 'sessions#create'     #新しいセッションの作成
  delete 'logout' => 'sessions#delete'  #セッションの削除(ログアウト)
  #resourcesメソッドを用いることで、HTTPメソッドとURLとアクションを自動的に紐付ける。
  #Tasksコントローラーのルーティングが自動生成される。
  resources :tasks
  resources :users
end
app/controllers/sessions_helper.rb
module SessionsHelper
  #渡されたユーザーでログインする。
  #攻撃者がこの情報をcookiesから盗むことができたとしても、本物のユーザーとしてログインすることはできない。
  def log_in(user)
    #ユーザーのブラウザ内の一時cookiesに暗号済みのユーザーIDが自動で生成される。
    #session[:名前]により、名前をつけてセッションに登録できる。
    session[:user_id] = user.id
  end

  #セッションに含まれる現在のユーザーを検索する。
  def current_user
    #@current_user = @current_user || User.find_by(id:params[:user_id])
    if session[:user_id]
      @current_user ||= User.find_by(id:params[:user_id])
    end
  end

  #ユーザーがログインしていればtrue,そうでなければfalseを返す。
  def logged_in?
    #current_user.nil?がfalseの場合(すなわち・・・)にtrueとなる。
    !current_user.nil?
  end

  #ログイン中のユーザーをログアウトする.
  def log_out
    sessions.delete(:user_id)
    @current_user = nil
  end
end
app/controllers/users_controller.rb
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    #ユーザーの保存が成功した時
    if @user.save
      #登録の終わったユーザーがデフォルトでログインするように変更する。
      log_in @user
      flash[:notice] = "Successfully registered a new user!"     #追加が成功した際に、flashメッセージを表示する。
      redirect_to '/'
    else
      #flash[:alert] = "Please enter at least one character."     #追加が成功した際に、flashメッセージを表示する。
      render 'users/new'
    end
  end

自分で試したこと

rails consoleでダミーデータを作成後、実際にログインしてみたところヘッダーの表示が変わりませんでした。

irb(main):004:0> User.create(name: "sampleitirou", email: "itirou@example.com", password: "hogehoge", password_confirmation: "hogehoge")
  TRANSACTION (0.1ms)  begin transaction
  User Exists? (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "itirou@example.com"], ["LIMIT", 1]]
  User Create (1.1ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES (?, ?, ?, ?, ?)  [["name", "sampleitirou"], ["email", "itirou@example.com"], ["created_at", "2021-08-22 13:00:23.183764"], ["updated_at", "2021-08-22 13:00:23.183764"], ["password_digest", "$2a$12$sPiY0t7zYoRvdzDdLk.4L.iDlvL3srRgFTIVW3ymtQFoTc1TWZ4Qe"]]
  TRANSACTION (1.4ms)  commit transaction
=> #<User id: 11, name: "sampleitirou", email: "itirou@example.com", created_at: "2021-08-22 13:00:23.183764000 +0000", updated_at: "2021-08-22 13:00:23.183764000 +0000", password_digest: [FILTERED]>
irb(main):005:0> 

ログイン画面です。パスワードは同じパスワードを打っており、もしログインに失敗したら、render 'new'よりログイン画面のままになります。
スクリーンショット 2021-08-22 22.01.25.png

ログイン後の画面です。ヘッダーの表記が変わらず、どこを修正すれば良いかわかりません。
スクリーンショット 2021-08-22 22.01.32.png

よろしくお願いします。

0

1Answer

まず簡単に確認しようと思えばこうやって見て、思っている変数なのかどうか

def log_in(user)
  Rails.logger.debug "#"*20
  Rails.logger.debug [user]
  Rails.logger.debug "#"*20
  session[:user_id] = user.id
end

渡されたuserが存在するものであれば、session、cookie自体が有効でない可能性はあります。

極々簡単な別なページを作って、

テスト用のコントローラー
def show
  session[:now] = Time.now.to_s
  render :show
end

sessionがまず動いているか確認するとか?

でも多分

@current_user ||= User.find_by(id:params[:user_id])

原因はここでしょうね。id: params[:user_id])(:コロン後はスペースで離したほうが見易い)

あとruby、railsなんでこの辺りはもうちょっと楽にかけます。

- user && user.authenticate 
+ user&.authenticate 

- !current_user.nil?
+ current_user.present?

safe navigation operator (ぼっち演算子):
object&.foo という形式のメソッド呼び出し形式が追加されました。これは object が nil でないときにメソッド foo を呼び出します。 Active Support の try! と似ていますが、メソッド名は文法的に必須であるという点が異なります。

0

Comments

  1. @suzu_ryuya

    Questioner
    返信いただきありがとうございます。仰る通り、id:params[:user_id]ではなくid:session[:user_id]でした。また、丁寧に回答していただきありがとうございます。とても勉強になります。

Your answer might help someone💌