Ассоциация Rails STI с подклассами

У меня странное поведение при извлечении коллекций из ассоциации has_many с rails 3 при использовании 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

и второе время:

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

, поскольку все они могут быть найдены по их ветке_идентификатора, но это создает проблемы в контроллере, если я хочу сделать ветку . employee.build, тогда класс по умолчанию будет User, и мне нужно где-то взломать столбец типа. На данный момент я обошел это с помощью:

  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})
    }

, но я действительно хотел бы избежать этого, если это возможно. Кто-нибудь, есть идеи?

РЕДАКТИРОВАТЬ:

finder_sql и counter_sql на самом деле не решили эту проблему для меня, потому что кажется, что родительские ассоциации не используют это и поэтому organization.employees, что has_many :employees, through: :branchesснова будет включать в выборку только класс User::Employee.

7
задан Tom Livesey 20 June 2012 в 12:06
поделиться