1

このサイトの Devise RDocs である Google を検索して、質問に対する回答を探しましたが、うまくいきませんでした。

4 つの Devise スコープ/ロールがあり、それぞれに独自の属性、ログイン ページ、および個別の Web フローがあるとします。

  • 学生
  • 教授
  • 学部長
  • 学部

これらはすべて User クラスを使用し、次の属性が共通しています。

  • ID
  • 名前
  • Eメール
  • パスワード
  • 役割

これを設定するために確立したルートの例を次に示します。

devise_for :students, :class_name => 'User'
devise_for :professors, :class_name => 'User'
devise_for :deans, :class_name => 'User'
devise_for :faculties, :class_name => 'User'
devise_for :users

次に、devise スコープのビューを生成し、それらをいじってみました。

その後、アプリケーション コントローラーにコードを追加して、すべてをルート パスにルーティングする Devise::RegistrationsController をオーバーライドする必要がありました。

def after_sign_in_path_for(resource)
 user_role = resource.role
 case user_role
   when "professor"
     professors_url
   when "faculty"
     faculties_url
   when "dean" 
     deans_url
   when "student"
     students_url
   else
     root_path       
  end 
end

def after_sign_out_path_for(resource)
  case resource
   when :faculty
     new_faculty_session_path
   when :professor
    new_professor_session_path
   when :dean 
     new_dean_session_path
   when :student
     new_student_session_path
   else
     root_path       
  end     
end

signed_in?などの優れたヘルパーにアクセスできますか? 上記のスコープのいずれかのユーザーがログインしているかどうかがわかります。素晴らしい!!! 現在、 current_userにも同様の機能が必要です。

次のヘルパーにアクセスできます。

  • 現在の学生
  • 現在の教授
  • current_dean
  • 現在の教員

それらは完全に機能しますが、ここに問題があります。これらすべてのスコープを共有するビューがあるとします。そのビューでcurrent_studentを試しても、教授としてログインしている場合は機能しません。

例: ユーザーがログインしている場合にログアウトできるようにするために、すべてのページに含めたいパーシャルがあります。これは、学生のために行った方法です。うまく動作します。

<% if student_signed_in? %>
 <div style="float: right;">Welcome <%= current_student.name %></div>
 <div>
    <%= link_to('Logout', destroy_student_session_path, :method => :delete) %>        
 </div>
<% end %>

私がやりたいことは、学生、学部長、教授、または教員としてログインしているかどうかに関係なく、すべてのスコープ/リソースをログアウトする機能を提供する次のようなものです。

<% if signed_in? %>
 <div style="float: right;">Welcome <%= current_resource.name %></div>
 <div>
    <%= link_to('Logout', destroy_resource_session_path, :method => :delete) %>        
 </div>
<% end %>

私の次のステップは、次のようにスコープを決定するために独自のヘルパー メソッドを追加することでした。

def current_resource
     current_professor unless current_professor.nil?
     current_student unless current_student.nil?
     current_dean unless current_dean.nil?
     current_faculty unless current_faculty.nil?
end

def destroy_resource_session_path
     destroy_professor_session_path unless current_professor.nil?
     destroy_student_session_path unless current_student.nil?
     destroy_dean_session_path unless current_dean.nil?
     destroy_faculty unless current_faculty.nil?
end

このアプローチがうまくいくなら、私はそうするでしょうが、将来さらに役割や一般的な機能を追加することにした場合、非常に非効率的で退屈に思えます...

より良い方法が必要ですか?これにより、Devise の使い方が間違っているか、どこかが欠けているように感じます。

4

3 に答える 3

0

上記の回答に対するコメントに基づいて、代替手段は、複数のRailsアプリケーション(役割ごとに1つ)を使用し、それらの間で同じDBを共有するか(SOに関するこの質問を参照)、認証と承認のためだけに別のアプリケーションを作成することです。それを介してすべてのサインインを管理します。

ただし、上記のソリューションは、1つのアプリを使用したくない場合のフォールバックにすぎません。今していることを続け、スコープを決定し、それぞれのケースに対処できるメソッドを作成することをお勧めします。

適切に設計されたメソッドを使用すると、これを少しうまく行うことができます。たとえば、 nil以外のいずれかに割り当てられてdestroy_resource_session_pathいる引数、を取り込むように変更してから、を呼び出します。これを行う方法をさらに詳しく説明するには:current_usercurrent_professor, ... current_facultydestroy_#{current_user}_session_path

アプリケーションで明確に定義されたロールを正確に必要とする必要はありません。各ロールをモデル/ビュー/コントローラーの異なるセットにルーティングするだけなので、ロールを決定し、リクエストをルーティングする個別のコントローラーを作成するのが最善の方法です。ユーザーの役割に基づいて適切なコントローラーに送信します。

編集:

一般的に、あなたはそれを正しい方法で進めていると思いますが、異なるユーザー(あなたが持っている2人のような)を扱うメソッドを、、、などのアクションを持つ別のコントローラーにコピーすると、より良くすることができdestroy_resource_session_pathますcurrent_resource。同様に、after_sign_in_path_forandafter_sign_out_path_forメソッドをその新しいコントローラーに追加します

重要なのは、新しいコントローラーはユーザーのタイプ間の区別を処理する必要があるため、新しいタイプのユーザーの追加は、そのコントローラーに数行追加して変更するだけの簡単なことroutes.rbです。

そのコントローラーにある役割のセットを保存するだけです。次に、セットを使用して存在するロールを把握するようにメソッドを変更できるため、セットにエントリをroutes.rb追加し、新しいロールを追加するためのエントリを追加するだけです。たとえば、次のように変更after_sign_in_path_for(resource)します。

def after_sign_in_path_for(resource)
  user_role = resource.role
  if (set_of_roles.include?(user_role))
    return #{user_role}_url
  else
    return root_path
  end
end

#{..}これがrubyで文字列を補間する方法であることに注意してください。したがって、rubyではJava#{user_role}_urlと同等です。user_role+"_url"

このようなメソッドでは、新しいロールを追加するために必要なのは、そのロールの新しいビューを作成し、で呼び出されるルートを定義して、role_nameroutes.rbロールを追加することだけset_of_rolesです。

シングルサインインのアイデアを使用する前に調査することをお勧めします。私はそれに慣れていませんが、SOでリンクした質問の回答は、物事を複雑にしすぎていると言っています。

于 2011-10-17T02:46:36.513 に答える
0

Ryan Bates のCanCanをチェックしましたか? これにより、Devise ユーザー モデルのみを使用し、ユーザー モデルのロールに基づいて能力を定義できます。can?次に、ヘルパー メソッドにアクセスしcannot?、自分の能力をさらに定義することができます。

編集:
属性を参照モデルに移動し、CanCan で Web フローを指示します。Web で見られる例は、CanCan が提供するすべての機能を常に示しているわけではありません。ランディング ページにリンクを配置して、それぞれが同じ Devise サインイン フォームを持つ適切なログイン ページに誘導することができます。のロジックを保持しafter_sign_in_path_for、CanCan で制限されたアクションをロックダウンします。これにより、ルートと全体的なアプリケーション ロジックおよび設計が簡素化されます。さらに、たった 1 つのモデルで Devise エラーのトラブルシューティングが 75% 容易になります。

于 2011-10-17T00:43:51.070 に答える