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

时间:2018-04-21 22:38:22

标签: ruby-on-rails ruby ruby-on-rails-5 metaprogramming

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

应用程序/模型/ 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

应用程序/模型/单位/ academy.rb

class Academy < Unit
end

应用程序/模型/单位/ faculty.rb

class Faculty < Unit
end

配置/环境/ 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无法为我生成范围,因为它有&#39;类型&#39;作为一个空数组。我的意思是单元模型的这一部分:

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

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

1 个答案:

答案 0 :(得分:2)

问题是后代类没有实例化。以下解决方法将帮助您实现您正在寻找的内容:

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

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

Faculty.allUnit.where(type: "Faculty")

相同

Academy.allUnit.where(type: "Academy")

相同