使用模型的后代动态生成范围

Dynamically Generating Scopes with Descendants of a Model

我在为我的 STI 模型动态生成范围时遇到问题。这是模型结构:

app/models/unit.rb

class Unit < ApplicationRecord
  def self.types
    descendants.map(&:name)
  end

  # Dynamically generate scopes for STI-related models
  types.each do |type|
    scope type.tableize.to_sym, -> { where(type: type) }
  end
end

app/models/units/academy.rb

class Academy < Unit
end

app/models/units/faculty.rb

class Faculty < Unit
end

config/environment/development.rb

config.eager_load = false

# Enable auto-load only for these files
Rails.application.reloader.to_prepare do
  Dir[
    Rails.root.join('app', 'models', '**', '*.rb')
  ].each { |file| require_dependency file }
end

当我在开发模式下进入 Rails 控制台时,我可以像这样轻松地检查单元类型:

Unit.types
["Academy", "Faculty"]

但是我无法达到预期的范围(例如 Unit.faculties、Unit.academies),因为 Rails 无法为我生成范围,因为它获得 'types' 作为空数组。我的意思是单元模型的这一部分:

types.each do |type|
  scope type.tableize.to_sym, -> { where(type: type) }
end

我可以从控制台检查类型,即使在开发模式下也是如此,但是当涉及到动态生成范围时,类型返回一个空数组。

问题是后代 类 没有实例化。以下解决方法将帮助您实现您的目标:

def self.types
  ActiveRecord::Base.connection.tables.map {|t| t.classify.constantize rescue nil}.compact
  descendants.map(&:name)
end

但就我个人而言,我认为您根本不需要这些范围,因为在后代 类 上调用 all 将提供查询:

Faculty.all 等同于 Unit.where(type: "Faculty")

Academy.all 等同于 Unit.where(type: "Academy")