当前位置:  开发笔记 > 编程语言 > 正文

有没有办法在Rails应用程序中获取所有模型的集合?

如何解决《有没有办法在Rails应用程序中获取所有模型的集合?》经验,为你挑选了14个好方法。

有没有办法可以在Rails应用程序中获得所有模型的集合?

基本上,我可以这样做: -

Models.each do |model|
  puts model.class.name
end

sj26.. 376

Rails 3,4和5的整个答案是:

如果cache_classes关闭(默认情况下它在开发中关闭,但在生产中关闭):

Rails.application.eager_load!

然后:

ActiveRecord::Base.descendants

这样可以确保应用程序中的所有模型(无论它们在何处)都已加载,并且还会加载任何提供模型的宝石.

这也适用于继承的类ActiveRecord::Base,比如ApplicationRecord在Rails 5中,并且只返回后代的子树:

ApplicationRecord.descendants

如果您想了解更多关于如何做到这一点,检查出的ActiveSupport :: DescendantsTracker.



1> sj26..:

Rails 3,4和5的整个答案是:

如果cache_classes关闭(默认情况下它在开发中关闭,但在生产中关闭):

Rails.application.eager_load!

然后:

ActiveRecord::Base.descendants

这样可以确保应用程序中的所有模型(无论它们在何处)都已加载,并且还会加载任何提供模型的宝石.

这也适用于继承的类ActiveRecord::Base,比如ApplicationRecord在Rails 5中,并且只返回后代的子树:

ApplicationRecord.descendants

如果您想了解更多关于如何做到这一点,检查出的ActiveSupport :: DescendantsTracker.


真棒!这应该是公认的答案.对于在rake任务中使用它的任何人:让你的任务依赖于`:environment`来实现`eager_load!`.
@ Ajedi32不完整,可以在这些目录之外定义模型,特别是在使用带模型的引擎时.稍微好一点,至少是全部`Rails.paths ["app/models"].现有的目录.渴望加载整个应用程序是一个更完整的答案,并将确保绝对没有任何地方可以定义模型.
@ Ajedi32再次,不是完整的答案.如果你只想加载模型,那么试试:`Rails.application.paths ["app/models"].eager_load!`
我得到了sj26的意思,但也许有一点错误:据我所知,在开发环境中,cache_classes关闭(false),这就是为什么你需要手动加载应用程序来访问所有模型的原因.[在此解释](http://guides.rubyonrails.org/v3.2.13/configuring.html)

2> kikito..:

万一有人偶然发现这个,我有另一个解决方案,不依赖于读取或扩展Class类......

ActiveRecord::Base.send :subclasses

这将返回一个类数组.所以你可以这样做

ActiveRecord::Base.send(:subclasses).map(&:name)


在Rails 3中,它已被更改为`ActiveRecord :: Base.descendants`
感谢Rails 3提示.对于其他任何人来说,你仍然需要在"ActiveRecord :: Base.descendants"列出它们之前"触摸"模型.
为什么不使用`ActiveRecord :: Base.subclasses`但必须使用`send`?此外,似乎你必须在它出现之前"触摸"模型,例如`c = Category.new`它会出现.否则,它不会.
您必须使用"发送",因为:子类成员受到保护.
从技术上讲,在Rails 3中你有子类*和*后代,它们意味着不同的东西.

3> Vincent Robe..:

编辑:看看评论和其他答案.有比这更聪明的答案!或者尝试将此作为社区维基进行改进.

模型不会将自己注册到主对象,所以不,Rails没有模型列表.

但您仍然可以查看应用程序的models目录的内容......

Dir.foreach("#{RAILS_ROOT}/app/models") do |model_path|
  # ...
end

编辑:另一个(狂野的)想法是使用Ruby反射来搜索扩展ActiveRecord :: Base的每个类.不知道如何列出所有课程,但...

编辑:为了好玩,我找到了列出所有课程的方法

Module.constants.select { |c| (eval c).is_a? Class }

编辑:最后成功列出所有模型而不查看目录

Module.constants.select do |constant_name|
  constant = eval constant_name
  if not constant.nil? and constant.is_a? Class and constant.superclass == ActiveRecord::Base
    constant
  end
end

如果你也想处理派生类,那么你需要测试整个超类链.我是通过向Class类添加一个方法来实现的:

class Class
  def extend?(klass)
    not superclass.nil? and ( superclass == klass or superclass.extend? klass )
  end
end

def models 
  Module.constants.select do |constant_name|
    constant = eval constant_name
    if not constant.nil? and constant.is_a? Class and constant.extend? ActiveRecord::Base
    constant
    end
  end
end


此外,重要的是要注意,通过常量方法搜索模型将不包括自应用程序启动以来未引用的任何内容,因为它仅按需加载模型.
仅供参考,我为两种方法计时只是为了好玩.查找目录比通过类搜索快一个数量级.这可能是显而易见的,但现在你知道:)
我更喜欢'Kernel.const_get constant_name'到'eval constant_name'.
Rails 3中不再提供`RAILS_ROOT`.而是使用`Dir.glob(Rails.root.join('app/models/*'))`

4> lightyrs..:
ActiveRecord::Base.connection.tables.map do |model|
  model.capitalize.singularize.camelize
end

将返回

["Article", "MenuItem", "Post", "ZebraStripePerson"]

附加信息如果要在没有模型的情况下调用对象名称上的方法:字符串未知方法或变量错误使用此方法

model.classify.constantize.attribute_names


这将获得所有表格,而不仅仅是模型,因为有些表格并不总是具有关联模型.

5> jaime..:

我找了办法做到这一点,最后选择了这种方式:

in the controller:
    @data_tables = ActiveRecord::Base.connection.tables

in the view:
  <% @data_tables.each do |dt|  %>
  
<%= dt %> <% end %>

来源:http://portfo.li/rails/348561-how-can-one-list-all-database-tables-from-one-project


这对单表继承不起作用.
一些有用的方法:`ActiveRecord :: Base.connection.tables.each {| t | begin puts"%s:%d"%[t.humanize,t.classify.constantize.count] rescue nil end}`有些模型可能没有被激活,因此你需要拯救它.
适应@ Andrei的一点:`model_classes = ActiveRecord :: Base.connection.tables.collect {| t | t.classify.constantize rescue nil} .compact`

6> Nimir..:

对于Rails5模型现在是子类,ApplicationRecord以便获取您的应用程序中所有模型的列表:

ApplicationRecord.descendants.collect { |type| type.name }

或更短:

ApplicationRecord.descendants.collect(&:name)

如果您处于开发模式,则需要先加载模型:

Rails.application.eager_load!



7> Aditya Sangh..:

我认为@hnovick的解决方案很酷,如果你没有无桌面型号.该解决方案也适用于开发模式

我的方法略有不同但是 -

ActiveRecord::Base.connection.tables.map{|x|x.classify.safe_constantize}.compact

classify很适合从字符串中正确地给出类的名称.safe_constantize确保您可以安全地将其转换为类而不会抛出异常.如果您的数据库表不是模型,则需要这样做.紧凑,以便删除枚举中的任何nils.


那真是太棒了@Aditya Sanghi.我不知道'safe_constantize`.

8> Jordan Micha..:

如果你只想要类名:

ActiveRecord::Base.descendants.map {|f| puts f}

只需在Rails控制台中运行它,仅此而已.祝好运!

编辑:@ sj26是对的,你需要先运行它才能调用后代:

Rails.application.eager_load!



9> 小智..:

这似乎对我有用:

  Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }
  @models = Object.subclasses_of(ActiveRecord::Base)

Rails仅在使用模型时加载模型,因此Dir.glob行"需要"models目录中的所有文件.

一旦你有一个数组中的模型,你可以做你想的(例如在视图代码中):

<% @models.each do |v| %>
  
  • <%= h v.to_s %>
  • <% end %>



    10> vjt..:

    在一行: Dir['app/models/\*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }


    这个很好,因为在Rails 3中,默认情况下你的模型不会自动加载,因此上述许多方法都不会返回所有可能的模型.我的排列也捕获了插件和子目录中的模型:`Dir ['**/models/**/*.rb'].map {| f | File.basename(f,'.*').camelize.constantize}`
    @wbharding这很不错,但是当它试图对我的rspec模型测试的名称进行constantize时它出错了.;-)

    11> Mark Locklea..:

    ActiveRecord::Base.connection.tables



    12> Adrian..:

    只需一行:

     ActiveRecord::Base.subclasses.map(&:name)
    


    这并没有显示我的所有模型.不知道为什么.事实上,这只是短暂的一小部分.
    在开发模式下执行之前,可能需要`Rails.application.eager_load!`.

    13> panteo..:

    我还不能评论,但我认为sj26答案应该是最佳答案.只是一个提示:

    Rails.application.eager_load! unless Rails.configuration.cache_classes
    ActiveRecord::Base.descendants
    



    14> nitanshu ver..:

    是的,有很多方法可以找到所有模型名称,但是我在gem model_info中所做的是,它将为您提供甚至包括在gem中的所有模型。

    array=[], @model_array=[]
    Rails.application.eager_load!
    array=ActiveRecord::Base.descendants.collect{|x| x.to_s if x.table_exists?}.compact
    array.each do |x|
      if  x.split('::').last.split('_').first != "HABTM"
        @model_array.push(x)
      end
      @model_array.delete('ActiveRecord::SchemaMigration')
    end
    

    然后简单地打印这个

    @model_array
    

    推荐阅读
    可爱的天使keven_464
    这个屌丝很懒,什么也没留下!
    DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
    Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有