223

Rails アプリのすべてのモデルのコレクションを取得する方法はありますか?

基本的に、次のようなことができますか: -

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

29 に答える 29

422

Rails 3、4、および 5 の全体的な答えは次のとおりです。

オフの場合cache_classes(デフォルトでは、開発ではオフですが、本番環境ではオンです):

Rails.application.eager_load!

それで:

ActiveRecord::Base.descendants

これにより、アプリケーション内のすべてのモデルがどこにあるかに関係なくロードされ、モデルを提供するために使用しているすべての gem もロードされます。

これは、Rails 5 のActiveRecord::Baseようにを継承するクラスでも機能し、その子孫のサブツリーのみを返す必要があります。ApplicationRecord

ApplicationRecord.descendants

これがどのように行われるかについて詳しく知りたい場合は、 ActiveSupport::DescendantsTrackerを調べてください。

于 2012-05-23T02:52:32.927 に答える
120

誰かがこれにつまずいた場合に備えて、ディレクトリの読み取りやクラスクラスの拡張に依存しない別の解決策があります...

ActiveRecord::Base.send :subclasses

これにより、クラスの配列が返されます。だから、あなたはそれを行うことができます

ActiveRecord::Base.send(:subclasses).map(&:name)
于 2010-01-12T10:50:42.427 に答える
103

編集:コメントと他の答えを見てください。これより賢い答えがあります!または、コミュニティwikiとしてこれを改善してみてください。

モデルはマスターオブジェクトに登録されないため、Railsにはモデルのリストがありません。

ただし、アプリケーションのモデルディレクトリのコンテンツを確認することはできます...

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
于 2009-02-05T16:17:39.543 に答える
70
ActiveRecord::Base.connection.tables.map do |model|
  model.capitalize.singularize.camelize
end

戻ります

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

追加情報model:string 不明なメソッドまたは変数エラーなしでオブジェクト名のメソッドを呼び出したい場合は、これを使用します

model.classify.constantize.attribute_names
于 2011-12-08T21:34:29.690 に答える
39

Rails5モデルはサブクラスになったため、アプリ内のすべてのモデルのリストを取得するには、のようにします。ApplicationRecord

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

または短い:

ApplicationRecord.descendants.collect(&:name)

開発モードの場合は、次の前にモデルを熱心にロードする必要があります。

Rails.application.eager_load!
于 2016-03-29T07:06:33.397 に答える
34

私はこれを行う方法を探し、最終的にこの方法を選択しました。

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

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

ソース: http: //portfo.li/rails/348561-how-can-one-list-all-database-tables-from-one-project

于 2011-01-04T20:30:47.100 に答える
23

テーブルのないモデルがない場合、@ hnovickのソリューションはクールなものだと思います。このソリューションは、開発モードでも機能します

ただし、私のアプローチは微妙に異なります-

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

classify は、文字列から適切にクラスの名前を与えることになっています。safe_constantize は、例外をスローすることなく安全にクラスに変換できることを保証します。これは、モデルではないデータベース テーブルがある場合に必要です。列挙内の nil が削除されるようにコンパクトにします。

于 2012-05-21T07:27:02.543 に答える
21

クラス名だけが必要な場合:

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

Rails コンソールで実行するだけです。幸運を!

編集:@ sj26は正しいです。子孫を呼び出す前に、これを最初に実行する必要があります:

Rails.application.eager_load!
于 2014-01-05T05:28:39.723 に答える
17

これは私にとってはうまくいくようです:

  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| %>
  <li><%= h v.to_s %></li>
<% end %>
于 2009-02-06T16:49:19.587 に答える
11

ActiveRecord::Base.connection.tables

于 2012-04-16T14:35:09.423 に答える
11

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

于 2010-03-11T15:42:38.410 に答える
7

たった1行で:

 ActiveRecord::Base.subclasses.map(&:name)
于 2012-07-19T14:08:58.493 に答える
7

はい、すべてのモデル名を見つける方法はたくさんありますが、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
于 2017-04-28T06:22:26.753 に答える
2
Module.constants.select { |c| (eval c).is_a?(Class) && (eval c) < ActiveRecord::Base }
于 2012-03-27T12:14:33.503 に答える
1

これは私にとってはうまくいきました。上記のすべての投稿に感謝します。これにより、すべてのモデルのコレクションが返されます。

models = []

Dir.glob("#{Rails.root}/app/models/**/*.rb") do |model_path|
  temp = model_path.split(/\/models\//)
  models.push temp.last.gsub(/\.rb$/, '').camelize.constantize rescue nil
end
于 2013-11-13T23:02:44.320 に答える
1

すべてのモデルを属性とともに印刷する必要があるため、これに出くわしました(@Aditya Sanghiのコメントに基づいて構築されています):

ActiveRecord::Base.connection.tables.map{|x|x.classify.safe_constantize}.compact.each{ |model| print "\n\n"+model.name; model.new.attributes.each{|a,b| print "\n#{a}"}}
于 2013-10-23T06:24:36.930 に答える
1

Rails 4でこれらの回答の多くを試してみましたが失敗しました(神のために1つまたは2つ変更されました)、独自の回答を追加することにしました。ActiveRecord::Base.connection を呼び出してテーブル名をプルしたものは機能しましたが、望んでいないいくつかのモデル (app/models/ 内のフォルダー内) を非表示にしたため、必要な結果が得られませんでした消去:

def list_models
  Dir.glob("#{Rails.root}/app/models/*.rb").map{|x| x.split("/").last.split(".").first.camelize}
end

それをイニシャライザに入れて、どこからでも呼び出すことができます。不必要なマウスの使用を防ぎます。

于 2013-11-14T22:25:07.780 に答える
1

これは、複雑なRailsアプリ(Squareを動かしているアプリ)で精査されたソリューションです

def all_models
  # must eager load all the classes...
  Dir.glob("#{RAILS_ROOT}/app/models/**/*.rb") do |model_path|
    begin
      require model_path
    rescue
      # ignore
    end
  end
  # simply return them
  ActiveRecord::Base.send(:subclasses)
end

このスレッドの回答の最良の部分を取り、それらを組み合わせて最も単純で完全なソリューションにします。これは、モデルがサブディレクトリにある場合を処理し、set_table_name などを使用します。

于 2013-06-10T12:41:12.697 に答える
0

すべてのモデルが app/models にあり、サーバーに grep と awk があると仮定すると (ほとんどの場合)、

# extract lines that match specific string, and print 2nd word of each line
results = `grep -r "< ActiveRecord::Base" app/models/ | awk '{print $2}'`
model_names = results.split("\n")

Rails.application.eager_load!を使用して各ファイルをループするよりも高速 ですDir

編集:

この方法の欠点は、ActiveRecord から間接的に継承するモデル (例: FictionalBook < Book) を見逃すことです。Rails.application.eager_load!; ActiveRecord::Base.descendants.map(&:name)少し遅いですが、最も確実な方法はです。

于 2015-10-08T21:15:59.320 に答える
0
def load_models_in_development
  if Rails.env == "development"
    load_models_for(Rails.root)
    Rails.application.railties.engines.each do |r|
      load_models_for(r.root)
    end
  end
end

def load_models_for(root)
  Dir.glob("#{root}/app/models/**/*.rb") do |model_path|
    begin
      require model_path
    rescue
      # ignore
    end
  end
end
于 2013-08-22T05:29:45.000 に答える
0

これを確認できます

@models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize}
于 2013-05-03T10:55:08.397 に答える
0

誰かが役に立つと思ったら、ここにこの例を投げるだけです。ソリューションは、この回答https://stackoverflow.com/a/10712838/473040に基づいています。

外部へのプライマリ ID として使用される列があるとします(ここでpublic_uidそれを行う理由を見つけることができます) 。

ここで、既存のモデルの束にこのフィールドを導入し、まだ設定されていないすべてのレコードを再生成したいとします。あなたはこのようにすることができます

# lib/tasks/data_integirity.rake
namespace :di do
  namespace :public_uids do
    desc "Data Integrity: genereate public_uid for any model record that doesn't have value of public_uid"
    task generate: :environment do
      Rails.application.eager_load!
      ActiveRecord::Base
        .descendants
        .select {|f| f.attribute_names.include?("public_uid") }
        .each do |m| 
          m.where(public_uid: nil).each { |mi| puts "Generating public_uid for #{m}#id #{mi.id}"; mi.generate_public_uid; mi.save }
      end 
    end 
  end 
end

あなたは今実行することができますrake di:public_uids:generate

于 2016-10-06T09:57:36.557 に答える