Có cách nào để có được bộ sưu tập tất cả các Mô hình trong ứng dụng Rails của bạn không?


201

Có cách nào để bạn có thể nhận được một bộ sưu tập tất cả các Mô hình trong ứng dụng Rails của mình không?

Về cơ bản, tôi có thể làm như:

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

1
Nếu bạn cần thu thập tất cả các mô hình bao gồm các mô hình động cơ / đường ray Rails, hãy xem câu trả lời của @jaime
Andrei

Không hoạt động trên đường ray 5.1
aks

Câu trả lời:


98

EDIT: Nhìn vào các ý kiến ​​và câu trả lời khác. Có câu trả lời thông minh hơn câu trả lời này! Hoặc cố gắng cải thiện cái này như wiki cộng đồng.

Các mô hình không tự đăng ký vào một đối tượng chính, vì vậy không, Rails không có danh sách các mô hình.

Nhưng bạn vẫn có thể xem nội dung của thư mục mô hình của ứng dụng của bạn ...

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

EDIT: Một ý tưởng (hoang dã) khác là sử dụng phản chiếu Ruby để tìm kiếm mọi lớp mở rộng ActiveRecord :: Base. Không biết làm thế nào bạn có thể liệt kê tất cả các lớp mặc dù ...

EDIT: Để giải trí, tôi đã tìm ra cách liệt kê tất cả các lớp

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

EDIT: Cuối cùng đã thành công trong việc liệt kê tất cả các mô hình mà không cần nhìn vào các thư mục

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

Nếu bạn cũng muốn xử lý lớp dẫn xuất, thì bạn sẽ cần phải kiểm tra toàn bộ chuỗi siêu lớp. Tôi đã làm điều đó bằng cách thêm một phương thức vào lớp 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

6
FYI, tôi hẹn giờ cả hai phương pháp chỉ để cho vui. Tra cứu các thư mục là một thứ tự cường độ nhanh hơn so với tìm kiếm mặc dù các lớp. Điều đó có thể rõ ràng, nhưng bây giờ bạn đã biết :)
Edward Anderson

9
Ngoài ra, điều quan trọng cần lưu ý là việc tìm kiếm các mô hình thông qua các phương thức hằng sẽ không bao gồm bất cứ điều gì chưa được tham chiếu kể từ khi ứng dụng bắt đầu, vì nó chỉ tải các mô hình theo yêu cầu.
Edward Anderson

4
Tôi thích 'Kernel.const_get Constant_name' hơn 'eval hằng_name'.
Jeremy Weathers

3
RAILS_ROOTkhông còn khả dụng trong Rails 3. Thay vào đó, hãy sử dụngDir.glob(Rails.root.join('app/models/*'))
fanaugen

1
Trên thực tế, các mô hình tự đăng ký là con cháu của ActiveRecord::Basebây giờ, vì vậy nếu bạn háo hức tải tất cả các mô hình thì bạn có thể lặp lại chúng một cách dễ dàng. Xem câu trả lời của tôi dưới đây.
sj26

393

Toàn bộ câu trả lời cho Rails 3, 4 và 5 là:

Nếu cache_classesbị tắt (theo mặc định, nó sẽ bị phát triển, nhưng đang trong quá trình sản xuất):

Rails.application.eager_load!

Sau đó:

ActiveRecord::Base.descendants

Điều này đảm bảo tất cả các mô hình trong ứng dụng của bạn, bất kể chúng ở đâu, được tải và bất kỳ đá quý nào bạn đang sử dụng cung cấp các mô hình cũng được tải.

Điều này cũng sẽ hoạt động trên các lớp kế thừa từ ActiveRecord::Base, như ApplicationRecordtrong Rails 5 và chỉ trả về cây con của con cháu:

ApplicationRecord.descendants

Nếu bạn muốn biết thêm về cách thực hiện, hãy xem ActiveSupport :: DescendantsTracker .


33
Tuyệt vời! Đây phải là câu trả lời được chấp nhận. Đối với bất cứ ai sử dụng này trong một nhiệm vụ rake: Làm nhiệm vụ của bạn phụ thuộc vào :environmentcho eager_load!đến công việc.
Jo Liss

1
Hoặc, như một sự thay thế nhanh hơn một chút Rails.application.eager_load!, bạn chỉ có thể tải các mô hình:Dir.glob(Rails.root.join('app/models/*')).each do |x| require x end
Ajedi32

5
@ Ajedi32 chưa hoàn thành, các mô hình có thể được xác định bên ngoài các thư mục đó, đặc biệt là khi sử dụng các công cụ với các mô hình. Tốt hơn một chút, ít nhất là toàn cầu tất cả các Rails.paths["app/models"].existentthư mục. Háo hức tải toàn bộ ứng dụng là một câu trả lời đầy đủ hơn và sẽ đảm bảo rằng không còn chỗ nào cho các mô hình được xác định.
sj26

2
Tôi hiểu ý nghĩa của sj26 nhưng có thể có một lỗi nhỏ: theo như tôi biết trong môi trường phát triển, cache_groupes bị tắt (sai) đó là lý do tại sao bạn cần tải ứng dụng một cách thủ công để truy cập tất cả các mô hình. giải thích tại đây
masciugo

3
@ Ajedi32 một lần nữa, không phải là câu trả lời đầy đủ. Nếu bạn muốn háo hức chỉ tải các mô hình thì hãy thử:Rails.application.paths["app/models"].eager_load!
sj26

119

Chỉ trong trường hợp bất kỳ ai vấp phải vấn đề này, tôi đã có một giải pháp khác, không dựa vào việc đọc thư mục hoặc mở rộng lớp Lớp ...

ActiveRecord::Base.send :subclasses

Điều này sẽ trả về một mảng các lớp. Vì vậy, bạn có thể làm

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

8
Tại sao bạn không sử dụng ActiveRecord::Base.subclassesmà phải sử dụng send? Ngoài ra, có vẻ như bạn phải "chạm" vào mô hình trước khi nó xuất hiện, ví dụ c = Category.newvà nó sẽ hiển thị. Nếu không, nó sẽ không.
cực tính

52
Trong Rails 3, điều này đã được đổi thànhActiveRecord::Base.descendants
Tobias Cohen

3
Bạn phải sử dụng "gửi" vì thành viên: lớp con được bảo vệ.
Kevin Rood

11
Cảm ơn các mẹo 3 Rails. Đối với bất kỳ ai khác đi cùng, bạn vẫn cần phải "chạm" vào các mô hình trước khi ActiveRecord::Base.descendantsliệt kê chúng.
nfm

3
Về mặt kỹ thuật trong Rails 3 bạn có các lớp con hậu duệ, chúng có nghĩa là những thứ khác nhau.
sj26

67
ActiveRecord::Base.connection.tables.map do |model|
  model.capitalize.singularize.camelize
end

sẽ trở lại

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

Thông tin bổ sung Nếu bạn muốn gọi một phương thức trên tên đối tượng mà không có mô hình: phương thức không xác định chuỗi hoặc lỗi biến sử dụng

model.classify.constantize.attribute_names

8
Điều này sẽ giúp bạn có tất cả các bảng, không chỉ các mô hình, vì một số bảng không phải lúc nào cũng có các mô hình liên kết.
Courtimas

Câu trả lời này nên được coi là không chính xác vì nó khả thi (và phổ biến trong các thiết lập kế thừa) để định cấu hình tên của bảng thành một cái gì đó khác với tên số nhiều của mô hình. Câu trả lời này cho câu trả lời đúng ngay cả khi thiết lập lệch khỏi cấu hình mặc định.
lorefnon

trong một số trường hợp, điều này hoạt động tốt hơn ActiveRecord::Base.send :subclasses- tìm kiếm tên bảng là một ý tưởng tốt. Tự động tạo tên mô hình có thể có vấn đề như lorefnon đã đề cập.
Tilo

.capitalize.singularize.camelizecó thể được thay thế để .classify.
Maxim

34

Tôi đã tìm cách để làm điều này và cuối cùng đã chọn cách này:

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

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

nguồn: http://portfo.li/rails/348561-how-can-one-list-all-database-tables-from-one-project


1
Đây là cách duy nhất tôi có thể nhận được TẤT CẢ các mô hình, bao gồm các mô hình động cơ Rails được sử dụng trong ứng dụng. Cảm ơn vì tiền hỗ trợ!
Andrei

2
Một vài phương pháp hữu ích: ActiveRecord::Base.connection.tables.each{|t| begin puts "%s: %d" % [t.humanize, t.classify.constantize.count] rescue nil end}Một số mô hình có thể không được kích hoạt do đó bạn cần phải giải cứu nó.
Andrei

2
Thích nghi @ Andrei's một chút: model_classes = ActiveRecord::Base.connection.tables.collect{|t| t.classify.constantize rescue nil }.compact
Max Williams

30

Đối với Rails5 mô hình hiện nay là lớp con của ApplicationRecordnhư vậy để có được danh sách của tất cả các mẫu trong ứng dụng của bạn, bạn cần làm:

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

Hoặc ngắn hơn:

ApplicationRecord.descendants.collect(&:name)

Nếu bạn đang ở chế độ dev, bạn sẽ cần phải háo hức tải các mô hình trước:

Rails.application.eager_load!

1
Tôi cho rằng điều này sẽ yêu cầu các lớp đã được tải và sẽ cho kết quả không đầy đủ trong môi trường phát triển với tính năng tự động tải. Tôi sẽ không downvote nhưng có lẽ điều này nên được đề cập trong câu trả lời.
lorefnon

đủ giá vé, cập nhật
N Elli

Tôi đang trên Rails 6.0.2 và háo hức! đã không làm cho phương thức con cháu trả về bất cứ thứ gì ngoại trừ một mảng trống.
jgomo3

23

Tôi nghĩ rằng giải pháp của @ hnovick là một giải pháp tuyệt vời nếu bạn không có các mô hình không có bảng. Giải pháp này cũng sẽ hoạt động trong chế độ phát triển.

Cách tiếp cận của tôi rất khác biệt mặc dù -

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

phân loại cũng được cho là cung cấp cho bạn tên của lớp từ một chuỗi đúng . safe_constantize đảm bảo rằng bạn có thể biến nó thành một lớp an toàn mà không cần ném ngoại lệ. Điều này là cần thiết trong trường hợp bạn có các bảng cơ sở dữ liệu không phải là mô hình. nhỏ gọn để bất kỳ nils trong liệt kê được loại bỏ.


3
Thật tuyệt vời @Aditya Sanghi. Tôi không biết về safe_constantize.
lightyrs

Đối với đường ray 2.3.x, hãy sử dụng: ActiveRecord :: Base.connection.tables.map {| x | x. Classify.constantify cứu nil} .compact
iheggie

@iheggie Nói chung là tốt hơn để đăng nó như một câu trả lời riêng biệt hơn là chỉnh sửa nó vào bài viết hiện có.
Pokechu22

cảm ơn, tôi thấy bạn trả lời phù hợp nhất với tôi #adiya
ảo ảnh

21

Nếu bạn chỉ muốn tên lớp:

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

Chỉ cần chạy nó trong bảng điều khiển Rails, không có gì hơn. Chúc may mắn!

EDIT: @ sj26 là đúng, bạn cần chạy cái này trước khi bạn có thể gọi con cháu:

Rails.application.eager_load!

Chỉ cần những gì tôi muốn. Cảm tạ!
hoàng hôn

Gọi mapvới puts? Tôi không nhận được điểm nên làActiveRecord::Base.descendants.map(&:model_name)
Nuno Costa

Bạn có thể làm theo cách đó, nhưng chúng sẽ ở trong một mảng, thay vì theo từng dòng, ở định dạng dễ đọc hơn nhiều.
Jordan Michael Rushing

17

Điều này dường như làm việc cho tôi:

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

Rails chỉ tải các mô hình khi chúng được sử dụng, vì vậy dòng Dir.glob "yêu cầu" tất cả các tệp trong thư mục mô hình.

Khi bạn có các mô hình trong một mảng, bạn có thể làm những gì bạn đang nghĩ (ví dụ: trong mã xem):

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

Cảm ơn bhousel. Ban đầu tôi đã đi theo phong cách tiếp cận này nhưng cuối cùng lại sử dụng giải pháp mà Vincent đã đăng ở trên vì điều đó có nghĩa là tôi cũng không phải "Mô hình hóa" tên tệp (nghĩa là loại bỏ bất kỳ _, viết hoa! Mỗi từ rồi tham gia họ một lần nữa).
mr_urf

với các thư mục con:...'/app/models/**/*.rb'
artemave

Object.subgroupes_of không được dùng nữa sau v2.3.8.
David J.

11

Trên một dòng: Dir['app/models/\*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }


7
Điều này là tốt vì trong Rails 3, các mô hình của bạn không được tự động tải theo mặc định, vì vậy nhiều phương thức trên sẽ không trả về tất cả các mô hình có thể. Hoán vị của tôi cũng nắm bắt các mô hình trong các plugin và thư mục con:Dir['**/models/**/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }
wbhending

2
@wbhending Điều đó khá hay, nhưng nó bị lỗi khi nó cố gắng liên tục hóa tên của các bài kiểm tra mô hình rspec của tôi. ;-)
Ajedi32

@wbhending giải pháp tốt đẹp nhưng nó bị hỏng khi bạn có các mô hình được đặt tên
Marcus Mansur

10

ActiveRecord::Base.connection.tables


Ngoài ra, một theo dõi tốt đẹp là <table_name> .column_names để liệt kê tất cả các cột trong bảng. Vì vậy, đối với bảng người dùng của bạn, bạn sẽ thực thi User.column_names
Mark Locklear

Điều này sẽ giúp bạn có tất cả các bảng, không chỉ các mô hình, vì một số bảng không phải lúc nào cũng có các mô hình liên kết.
Courtimas

7

Chỉ trong một dòng:

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

2
Điều đó không hiển thị tất cả các mô hình cho tôi. Không chắc chắn lý do tại sao. Thực tế, nó là một cặp đôi.
Courtimas

1
đã làm cho tôi. 'Chỉ trễ một chút để trả lời tất cả. cho nó thời gian
boulder_ruby

2
Có lẽ nó cần Rails.application.eager_load!trước khi thực hiện trong chế độ phát triển.
denis.peplin

7

Tôi chưa thể bình luận, nhưng tôi nghĩ câu trả lời sj26 nên là câu trả lời hàng đầu. Chỉ là một gợi ý:

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

6

Với Rails 6 , Zetiwerk trở thành trình tải mã mặc định.

Để tải háo hức, hãy thử:

Zeitwerk::Loader.eager_load_all

Sau đó

ApplicationRecord.descendants

5

Vâng, có nhiều cách bạn có thể tìm thấy tất cả các tên mô hình nhưng những gì tôi đã làm trong gem model_info của tôi là, nó sẽ cung cấp cho bạn tất cả các mô hình thậm chí có trong các viên đá quý.

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

sau đó chỉ cần in

@model_array

3

Điều này hoạt động cho Rails 3.2.18

Rails.application.eager_load!

def all_models
  models = Dir["#{Rails.root}/app/models/**/*.rb"].map do |m|
    m.chomp('.rb').camelize.split("::").last
  end
end

upvolt cho Rails.application.eager_load! ý tưởng
tương

3

Để tránh tải trước tất cả Rails, bạn có thể làm điều này:

Dir.glob("#{Rails.root}/app/models/**/*.rb").each {|f| require_dependency(f) }

allow_dependency (f) giống nhau Rails.application.eager_load! sử dụng. Điều này sẽ tránh các lỗi tập tin đã được yêu cầu.

Sau đó, bạn có thể sử dụng tất cả các loại giải pháp để liệt kê các mô hình AR, như ActiveRecord::Base.descendants


2
Module.constants.select { |c| (eval c).is_a?(Class) && (eval c) < ActiveRecord::Base }

ném TypeError: không chuyển đổi ngầm định Biểu tượng thành Chuỗi trong bảng điều khiển.
tuyết rơi

1

Đây là một giải pháp đã được hiệu đính với ứng dụng Rails phức tạp (Quảng trường cung cấp năng lượng)

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

Nó lấy những phần tốt nhất của câu trả lời trong chủ đề này và kết hợp chúng trong giải pháp đơn giản và kỹ lưỡng nhất. Điều này xử lý các trường hợp mô hình của bạn nằm trong thư mục con, sử dụng set_table_name, v.v.


1

Chỉ cần bắt gặp cái này, vì tôi cần in tất cả các mô hình với các thuộc tính của chúng (được xây dựng trên nhận xét của @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}"}}

1

Điều này làm việc cho tôi. Đặc biệt cảm ơn tất cả các bài viết ở trên. Điều này sẽ trả về một bộ sưu tập của tất cả các mô hình của bạn.

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

1

Các Railsdụng cụ phương pháp này descendants, nhưng các mô hình không nhất thiết phải bao giờ thừa hưởng từ ActiveRecord::Base, ví dụ, lớp bao gồm các mô-đunActiveModel::Model sẽ có hành vi tương tự như một mô hình, chỉ cần không sẽ được liên kết với một bảng.

Vì vậy, bổ sung cho những gì các đồng nghiệp ở trên, nỗ lực nhỏ nhất sẽ làm điều này:

Monkey Patch của lớp ClassRuby:

class Class
  def extends? constant
    ancestors.include?(constant) if constant != self
  end
end

và phương pháp models, bao gồm cả tổ tiên, như sau:

Phương thức Module.constantstrả về (một cách hời hợt) một tập hợp symbols, thay vì các hằng số, vì vậy, phương thức Array#selectcó thể được thay thế như bản vá con khỉ này của Module:

class Module

  def demodulize
    splitted_trail = self.to_s.split("::")
    constant = splitted_trail.last

    const_get(constant) if defines?(constant)
  end
  private :demodulize

  def defines? constant, verbose=false
    splitted_trail = constant.split("::")
    trail_name = splitted_trail.first

    begin
      trail = const_get(trail_name) if Object.send(:const_defined?, trail_name)
      splitted_trail.slice(1, splitted_trail.length - 1).each do |constant_name|
        trail = trail.send(:const_defined?, constant_name) ? trail.const_get(constant_name) : nil
      end
      true if trail
    rescue Exception => e
      $stderr.puts "Exception recovered when trying to check if the constant \"#{constant}\" is defined: #{e}" if verbose
    end unless constant.empty?
  end

  def has_constants?
    true if constants.any?
  end

  def nestings counted=[], &block
    trail = self.to_s
    collected = []
    recursivityQueue = []

    constants.each do |const_name|
      const_name = const_name.to_s
      const_for_try = "#{trail}::#{const_name}"
      constant = const_for_try.constantize

      begin
        constant_sym = constant.to_s.to_sym
        if constant && !counted.include?(constant_sym)
          counted << constant_sym
          if (constant.is_a?(Module) || constant.is_a?(Class))
            value = block_given? ? block.call(constant) : constant
            collected << value if value

            recursivityQueue.push({
              constant: constant,
              counted: counted,
              block: block
            }) if constant.has_constants?
          end
        end
      rescue Exception
      end

    end

    recursivityQueue.each do |data|
      collected.concat data[:constant].nestings(data[:counted], &data[:block])
    end

    collected
  end

end

Khỉ vá của String.

class String
  def constantize
    if Module.defines?(self)
      Module.const_get self
    else
      demodulized = self.split("::").last
      Module.const_get(demodulized) if Module.defines?(demodulized)
    end
  end
end

Và, cuối cùng, phương pháp mô hình

def models
  # preload only models
  application.config.eager_load_paths = model_eager_load_paths
  application.eager_load!

  models = Module.nestings do |const|
    const if const.is_a?(Class) && const != ActiveRecord::SchemaMigration && (const.extends?(ActiveRecord::Base) || const.include?(ActiveModel::Model))
  end
end

private

  def application
    ::Rails.application
  end

  def model_eager_load_paths
    eager_load_paths = application.config.eager_load_paths.collect do |eager_load_path|
      model_paths = application.config.paths["app/models"].collect do |model_path|
        eager_load_path if Regexp.new("(#{model_path})$").match(eager_load_path)
      end
    end.flatten.compact
  end

1
Dir.foreach("#{Rails.root.to_s}/app/models") do |model_path|
  next unless model_path.match(/.rb$/)
  model_class = model_path.gsub(/.rb$/, '').classify.constantize
  puts model_class
end

Điều này sẽ cung cấp cho bạn tất cả các lớp mô hình bạn có trong dự án của bạn.


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

0

Tôi đã thử rất nhiều câu trả lời trong số này không thành công trong Rails 4 (wow họ đã thay đổi một hoặc hai điều cho các vị thần) Tôi quyết định thêm câu trả lời của riêng mình. Những cái được gọi là ActiveRecord :: Base.connection và kéo tên bảng hoạt động nhưng không đạt được kết quả tôi muốn vì tôi đã ẩn một số mô hình (trong một thư mục bên trong ứng dụng / mô hình /) mà tôi không muốn xóa bỏ:

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

Tôi đặt nó trong một bộ khởi tạo và có thể gọi nó từ bất cứ đâu. Ngăn chặn việc sử dụng chuột không cần thiết.


0

có thể kiểm tra cái này

@models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize}

0

Giả sử tất cả các mô hình đều có trong ứng dụng / mô hình và bạn có grep & awk trên máy chủ của mình (phần lớn các trường hợp),

# 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")

Nó nhanh hơn Rails.application.eager_load!hoặc lặp qua từng tệp với Dir.

BIÊN TẬP:

Nhược điểm của phương pháp này là nó bỏ lỡ các mô hình gián tiếp kế thừa từ ActiveRecord (ví dụ FictionalBook < Book). Cách chắc chắn nhất là Rails.application.eager_load!; ActiveRecord::Base.descendants.map(&:name), mặc dù nó hơi chậm.


0

Tôi chỉ ném ví dụ này ở đây nếu có ai thấy nó hữu ích. Giải pháp dựa trên câu trả lời này https://stackoverflow.com/a/10712838/473040 .

Giả sử bạn có một cột public_uidđược sử dụng làm ID chính cho thế giới bên ngoài (bạn có thể tìm thấy lý do tại sao bạn muốn làm điều đó ở đây )

Bây giờ giả sử bạn đã giới thiệu trường này trên một loạt các Mô hình hiện có và bây giờ bạn muốn tạo lại tất cả các bản ghi chưa được thiết lập. Bạn có thể làm điều đó như thế này

# 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

bây giờ bạn có thể chạy rake di:public_uids:generate

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.