sql – Rails与子类的STI关联

前端之家收集整理的这篇文章主要介绍了sql – 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

期望的行为是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

因为它们都是从他们的branch_id中找到的,但这会在控制器中产生问题,如果我想做branch.employees.build那么该类将默认为User,我必须在某处修改type列.我现在已经解决了这个问题:

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还没有真正解决它,因为看起来父联想似乎没有使用它,所以organisation.employees has_many:employees,通过:: branches将再次只在选择中包含User :: Employee类.

解决方法

基本上,该问题仅存在于根据需要加载类的开发环境中. (在生产中,类被加载并保持可用.)

问题来自于,当您第一次运行Employee.find等调用时,解释器还没有看到Admins是一种Employee.

(请注意,它稍后使用IN(‘User :: Employee’,’User :: BranchAdmin’))

每次使用深度超过一级的模型类时都会发生这种情况,但仅限于开发模式.

子类始终自动加载其父层次结构.基类不会自动加载他们的子级别.

哈克修复:

您可以通过显式要求基类rb文件中的所有子类来强制在dev模式下执行正确的行为.

猜你在找的MsSQL相关文章