Tom*_*sey 7 sql activerecord ruby-on-rails sti
在使用STI时,从使用rails 3的has_many关联中获取集合时,我遇到了一些奇怪的行为.我有:
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
Run Code Online (Sandbox Code Playgroud)
期望的行为是branch.employees返回所有员工,包括分支管理员.分支管理员在访问它们时似乎只在此集合下"加载" branch.admins,这是从控制台输出的:
Branch.first.employees.count
=> 2
Branch.first.admins.count
=> 1
Branch.first.employees.count
=> 3
Run Code Online (Sandbox Code Playgroud)
这可以在生成的SQL中看到,第一次:
SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee') AND "users"."branch_id" = 1
Run Code Online (Sandbox Code Playgroud)
第二次:
SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee', 'User::BranchAdmin') AND "users"."branch_id" = 1
Run Code Online (Sandbox Code Playgroud)
我只需指定以下内容即可解决此问题:
class Branch < ActiveRecord::Base
has_many :employees, class_name: 'User'
has_many :admins, class_name: 'User::BranchAdmin'
end
Run Code Online (Sandbox Code Playgroud)
因为它们都是从他们的branch_id中找到的,但是这会在控制器中产生问题,如果我想这样做,branch.employees.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})
}
Run Code Online (Sandbox Code Playgroud)
但如果可能的话,我真的想避免这种情况.任何人,任何想法?
编辑:
该finder_sql和counter_sql还没有真正解决了这个问题对我来说,因为它似乎是家长协会不使用这一点,所以organisation.employees这has_many :employees, through: :branches将再次只包括User::Employee在选择类.
Sha*_*nce 20
基本上,该问题仅存在于根据需要加载类的开发环境中.(在生产中,类已加载并保持可用.)
问题来自于解释器还没有看到,这Admins是Employee你第一次运行Employee.find等调用时的类型.
(请注意以后使用IN ('User::Employee', 'User::BranchAdmin'))
每次使用深度超过一级的模型类时都会发生这种情况,但仅限于开发模式.
子类始终自动加载其父层次结构.基类不会自动加载他们的子级别.
哈克修复:
您可以通过显式要求基类rb文件中的所有子类来强制在dev模式下执行正确的行为.
| 归档时间: |
|
| 查看次数: |
8409 次 |
| 最近记录: |