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