2016-03-22 14 views
0

Railsアプリケーションでは、アプリケーションコントローラに2つのメソッドがあります。そのうちの1つはユーザーを認証します(ユーザーがログインしているかどうかを確認し、ログインしていない場合はログインするようにリダイレクトします)。他方はそのタスクの前半を実行する(すなわち、ユーザがログインしているかどうかをチェックする)。論理的に同一の2つのメソッドが同じタスクを実行しないのはなぜですか?

チェックが完了すると、ユーザーがログインしている場合、これらの方法はいずれも、User.findを使用して、現在サインインしているユーザーのユーザーオブジェクトに@current_user変数を設定します。

は旧:

protected 
def authenticate_user 
    if session[:user_id] 
    # set current user object to @current_user object variable 
    @current_user = User.find session[:user_id] 
    return true 
    else 
    flash[:notice] = "You must log in first." 
    flash[:color] = "invalid" 
    redirect_to(:controller => 'sessions', :action => 'login') 
    return false 
    end 
end 

後者:あなたが見ることができるように

def check_login_status 
    if session[:user_id] 
    @current_user = User.find session[:user_id] 
    return true 
    end 
end 

、これらの各方法の前半のためのロジックは同じです。ただし、authenticate_userは、@current_user変数を正しく設定します。レイアウトファイルにチェックを@current_user.nil? == true言う、のようにcheck_login_statusは(すべてでそれを設定していない

を。これは、レイアウトファイルの関連部分です。

<% if not @current_user.nil? %> 
    Logged in as <%= @current_user.username %> — 
    <a href="/logout">log out</a> — 
    <a href="/dashboard">dashboard</a> — 
    <a href="/contacts">contacts</a> — 
    <a href="/help">help</a> 
    <% if @current_user.is_admin %> 
    — <a href="/admin">admin</a> 
    <% end %> 
<% else %> 
    <a href="/login">log in</a> — 
    <a href="/sign-up">sign up</a> — 
    <a href="/help">help</a> 
<% end %> 

私が示されたリンクの第2のセットを取得します、私がログアウトしていたことを示す。

それでは、なぜ後者が正しく@current_user変数を設定していないのですか?それは(どういうわけか、私はそれを疑うが)マーキングprotectedを行うには何も持っていますか?

+1

後者のメソッドは実際に呼び出されていますか?多分、問題はルートにあり、コントローラではない。 –

+0

@ das-gはい、私は両方とも 'before_filter'呼び出しで使用しました。 – ArtOfCode

答えて

1

私は、最も可能性の高い説明は、check_login_statusが両方とも論理的に同等であるため、全く呼び出されていないということです。ただし、両方とも同じ認証ロジックを複製します。

認証ホイールの再作成を奨励​​する場合(学習目的以外では使用しないでください)、コントローラとビュー全体に認証ロジックが広がるのを避けるべきです。

代わりにヘルパーモジュールを使用して、認証用の単純なAPIを作成します。このモジュールは、ユーザーがセッションに保存されている方法を知っているアプリの一部のみでなければなりません:

module AuthorizationHelper 
    def current_user 
    return nil unless session[:user_id] 
    # conditional assignment so DB is only queried once! 
    @current_user ||= User.find(session[:user_id]) 
    end 

    def sign_in!(user) 
    reset_session 
    session[:user_id] = user.id 
    @current_user = user 
    end 

    def sign_out!(user) 
    reset_session 
    @current_user = nil 
    end 

    def signed_in? 
    current_user.present? 
    end 
end 

今はちょうどApplicationControllerでヘルパーを含めます。

class ApplicationController 
    include AuthorizationHelper 
    # ... 
end 

また、再利用可能で拡張可能な方法で許可を得たいと考えています。これを行う良い方法は、例外を発生させてrescue_fromでキャッシングすることです。

当社独自のエラークラスを作成することができます:

class User < ActiveRecord::Base 
    class AuthorizationError < StandardError; end 
end 

は、認証方法を追加できます:

module authorizationHelper 
    # .. 
    def authorize! 
    raise User::AuthorizationError unless signed_in? 
    end 
end 

今、私たちは私たちのコントローラでこれを使用することができます。

class ThingsController < ApplicationController 
    before_action :authorize! 
end 

しかし、そのありません非常に便利なので、アプリがクラッシュするだけです!

class ApplicationController 
    include AuthorizationHelper 
    rescue_from User::AuthorizationError, with: :deny_access 

    def deny_access 
    redirect_to(controller: 'sessions', action: 'login') and return 
    end 
end 
関連する問題