10

私はDevisesを認証に使用するRails 3.2アプリケーションで作業しています。ユーザーの役割を管理するために単一のテーブル継承を試みることにしましたが、すぐに問題に遭遇しました。私は現在、3つのユーザモデル、User < ActiveRecord,Admin < UserおよびCollaborator < Userを持っています。 AdminとCollaboratorはほとんどのユーザー列を共有しますが、動作と権限はわずかに異なります。私は管理者と協力者の私ProjectControllerで(と私が認証を必要とする他のコントローラ)を認証しようとすると、Rails 3.2 Appで複数のモデルを使用しているときにDeviseで認証を処理する方法

class User < ActiveRecord::Base 

    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable, :token_authenticatable 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :name, :password, :password_confirmation, :remember_me 

    before_save :ensure_authentication_token 

    [...] 

end 

class Admin < User 
    has_one :account, dependent: :destroy 
    attr_accessible :account_attributes 
    accepts_nested_attributes_for :account 
end 


class Collaborator < User 
    has_one :account 
end 

class Account < ActiveRecord::Base 
    attr_accessible :name 
    validates_presence_of :name 
    has_many :projects, dependent: :destroy 
    has_many :users 
end 

問題の牡羊座:私のモデルは、現在、このようになります

# Causes problem, no one can access anything. 
before_filter :authenticate_admin! 
before_filter :authenticate_collaborator! 

私が持っていた同様の問題そのための工夫のヘルパーメソッドであった。 CURRENT_USER、今私はcurrent_adminとcurrent_collaboratorを持って、私はフィルタとメソッドの前に作成することで、これを「解決」:

def set_current_user 
    @current_user = current_admin || current_collaborator 
end 

は工夫と私の認証の問題のために、類似または簡単な解決策はありますか、より別のアプローチをお勧めします単一のテーブル継承とは何でしょうか?

私の目標は、1.新しいユーザーがサインアップしたときに管理者になり、アカウントを作成するときにアカウントモデルも作成されます。 2.新しい(管理者)ユーザーは、追加のユーザーをコラボレーターになるアカウントに招待できます。 3.管理者と共同作業者は、異なる権限を持つ必要があります。コラボレータはサインアップ時に新しい「アカウント」を作成することはありません(会社は自分のアカウントモデルのより良い名前になる可能性があります)。そのため、管理者と共同編集者は、サインアップと編集のためにわずかに異なるフォームが必要になります。

ありがとうございました。

更新

私はちょっとフィルタの前に同様のを作成することによって、それを「解決」:おそらくよりエレガントなソリューションの

def authenticate! 
    if @current_user == current_admin 
    :authenticate_admin! 
    elsif @current_user == current_collaborator 
    :authenticate_collaborator! 
    end 
end 

提案がまだいただければ幸いです。

+0

を使用してこの問題を解決することができますが私の答えをテストするチャンスを得ますか? – blnc

答えて

1

すべての共通ロジックをモジュールに分け、同じテーブルのみを使用することができます。

module UserMethods 
    #... 
end 

class User < ActiveRecord::Base 
    include UserMethods 
    devise ... 

end 

class Admin < ActiveRecord::Base 
    include UserMethods 
    self.table_name = "users" 
    devise ... 
end 

とルートで別々にすべての工夫モデルを設定し、ビュー(必要であれば、Configuring Viewsを参照してください)。この場合、すべての異なるロジックを簡単に処理できます。

+0

ええ、ありがとう。それはうまくいくようです。しかし、このソリューションは現在のソリューションよりどのように優れていますか?私の新生児の質問には申し訳ありません。ここに別のものが来る。私は自分のロジックを少し変更することを考えており、ユーザーには、アカウントごとにAdminsまたはCollaborator、ユーザーとアカウントの多対1の関係の多くのアカウントを持たせることができます。まだ異なる役割を持っていますか?ありがとう! – Anders

+0

モジュールを含めるのではなく、すべてのロジックを共通モデルに抽出することができます(BaseUserなど)。ここにすべての関係を置きます。しかし、すべての異なるロジックは、デバイスまたはアトリビュートに関連して、モデルを分離することができます。私。それはあなたと私のアプローチが組み合わされているように見えます。私はOOPスタイルではないので、メソッドの条件ならば好きではありません。 – gayavat

3

ない、これはまだこれに対する解決策を必要とされているかどうかわから...

二重の認証を持っているために、よりエレガントな方法は、次の手順を実行することができます。そして、

private 

def authenticate! 
    :authenticate_admin! || :authenticate_collaborator! 
    @current_user = admin_signed_in? ? current_admin : current_collaborator 
end 

before_filterを呼び出します。認証します!

普遍的な '@current_user'変数が必要ない場合は、2行目を省略してください。

これが役に立ちます。

+0

失敗した場合はauthenticate_adminがリダイレクトするため、このソリューションは機能しません...アイデアはありますか?私はそれを働かせることができません – Rafal

+0

あなたは正しいです、これはもはや最新のバージョンでは動作しません。私は仕事を見つけることができるかどうかを見ます。 – blnc

+0

私の解決策で回答を追加しました – Rafal

5

あなたは、次の解決策

 
def authenticate! 
    if modelA_user_signed_in? 
     @current_user = current_modelA 
     true 
    else 
     authenticate_modelB! 
    end 

    end 
関連する問題