2012-06-20 18 views
6

STIを使用するときに、レール3とのhas_many関連付けからコレクションをフェッチするときに、いくつかの異常な動作が発生します。私が持っている:Rails STIとサブクラスの関連付け

class Branch < ActiveRecord::Base 
    has_many :employees, class_name: 'User::Employee' 
    has_many :admins, class_name: 'User::BranchAdmin' 
end 

class User < ActiveRecord::Base 
end 

class User::Employee < User 
    belongs_to :branch 
end 

class User::BranchAdmin < User::Employee 
end 

望ましい行動がbranch.employeesが分岐管理者を含むすべての従業員を返すことです。支店の管理者にのみ、このコンソールから出力され、彼らはbranch.adminsがアクセスしたときに、このコレクションの下に「ロードされた」ように見える:

Branch.first.employees.count 
=> 2 

Branch.first.admins.count 
=> 1 

Branch.first.employees.count 
=> 3 

これは、生成されたSQLで初めて見ることができます。

SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee') AND "users"."branch_id" = 1 

目と2回目:

SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee', 'User::BranchAdmin') AND "users"."branch_id" = 1 

私はちょうど指定することによってこの問題を解決することができます:

class Branch < ActiveRecord::Base 
    has_many :employees, class_name: 'User' 
    has_many :admins, class_name: 'User::BranchAdmin' 
end 

彼らはすべて彼らのBRANCH_IDから見つけることが、私はその後、クラスがUserがデフォルトになりますbranch.employees.buildをしたいと私はどこかのタイプの列でハックする必要がある場合、これは、コントローラで問題を作成するので。私は今のところこれを持っています:

has_many :employees, class_name: 'User::Employee', 
    finder_sql: Proc.new{ 
     %Q(SELECT users.* FROM users WHERE users.type IN   ('User::Employee','User::BranchAdmin') AND users.branch_id = #{id}) 
    }, 
    counter_sql: Proc.new{ 
     %Q(SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee', 'User::BranchAdmin') AND "users"."branch_id" = #{id}) 
    } 

しかし、私は本当にこれを避けたいと考えています。誰でも、どんなアイデアですか?

EDIT:親の会がこれを使用していないので、organisation.employeeshas_many :employees, through: :branchesことを再度選択のみでUser::Employeeクラスが含まれると思われるので、

finder_sqlとcounter_sqlは本当に私のためにそれを解決していません。

答えて

17

基本的に、この問題は、必要に応じてクラスがロードされる開発環境にのみ存在します。

Employee.findなどを初めて実行したときに、がEmployeeのタイプであることが、通訳者によってまだ理解されていないために問題が発生しています。

これは、複数のレベルの深されているモデルクラスを使用するたびに起こるが、唯一のDEVモードで(それは後でIN ('User::Employee', 'User::BranchAdmin')を使用することに注意してください)。

サブクラスは常にその親階層をオートロードします。基本クラスは子階層を自動ロードしません。

ハック - 修正:

あなたは明示的に基底クラスRBファイルからすべてのあなたの子供のクラスを要求することにより、DEVモードで正しい動作を強制することができます。

+2

これは素晴らしいキャッチです、ありがとう。とにかくモデルの構造は実際に変更されたので問題は消えましたが、私はそれが環境の影響であるとも考えていないと思います! –

2

:conditionsはありますか?

class Branch < ActiveRecord::Base 
    has_many :employees, class_name: 'User::Employee', :conditions => {:type => "User::Employee"} 
    has_many :admins, class_name: 'User::BranchAdmin', :conditions => {:type => "User::BranchAdmin"} 
end 

これが私の好ましい方法です。もう1つの方法は、多態性モデルにデフォルトスコープを追加することです。

class User::BranchAdmin < User::Employee 
    default_scope where("type = ?", name) 
end 
+0

私は条件を使用しようとしましたが、これも問題がありました。アプリの構造が変更されましたので、これについて心配する必要はありませんでした。これはレール3.2.7で修正されている可能性があります。 –

関連する問題