单表继承-附加类名

时间:2019-02-22 13:34:48

标签: ruby-on-rails ruby-on-rails-4 activerecord single-table-inheritance sti

我在Rails 4应用程序中遇到一种情况,我有STI,想通过其他type自定义默认查询。

课程:

class Candidate < ApplicationRecord
end

class Candidate::Site < Candidate
end

现在,如果我进行查询,则会得到如下结果:

> Candidate::Site.count
# SELECT COUNT(*) FROM "candidates" WHERE "candidates"."type" IN ('Candidate::Site')
=> 0

现在,在我的情况下,我想添加一个额外的type,该查询应每次查找。通过利用IN子句,可以触发我的预期查询:

SELECT COUNT(*) FROM "candidates" WHERE "candidates"."type" IN ('Candidate::Site', 'Site')

有人可以帮我控制这里的IN子句吗?预先感谢。

2 个答案:

答案 0 :(得分:0)

您可以这样查询:

Candidate.where(
  Candidate.inheritance_column => [Candidate::Site, Site, SomeOtherClass].map(&:sti_name)
).count

答案 1 :(得分:0)

详细研究并深入研究Rails STI源代码后,我发现我的场景将需要覆盖Rails的默认STI。以下是我实现目标所需要的:


class Candidate::Site

  # To enable renaming of Site to Candidate::Site
  # per ENG-9551, we need to:
  # 1. disable the 'type' column from using Rails' built-in STI
  self.inheritance_column = :_nonexistant_column_to_bypass_sti

  # 2. manually set the type column to Candidate::Site when we save,
  # so that new and edited records are saved as Candidate::Site
  before_save { self.type = 'Candidate::Site' }

  # 3. always report the type as a Candidate::Site
  def type
    'Candidate::Site'
  end

  # 4. and set a default scope which only reads type columns that are
  # 'Candidate::Site' or 'Site' so that STI
  # still appears to be the same as always
  default_scope { where(type: 'Candidate::Site').or(where(type: 'Site')) }

  ...
  ...
  ...
end

因此,现在使用Candidate::Site.create创建的任何新记录都将存储类型Candidate::Site,而查询将使用默认范围并同时考虑类型Candidate::SiteSite