Czy istnieje sposób, aby uzyskać kolekcję wszystkich modeli w aplikacji Rails?
Zasadniczo mogę zrobić:
Models.each do |model|
puts model.class.name
end
Czy istnieje sposób, aby uzyskać kolekcję wszystkich modeli w aplikacji Rails?
Zasadniczo mogę zrobić:
Models.each do |model|
puts model.class.name
end
Odpowiedzi:
EDYCJA: Spójrz na komentarze i inne odpowiedzi. Są mądrzejsze odpowiedzi niż ta! Lub spróbuj ulepszyć ten jako wiki społeczności.
Modele nie rejestrują się w obiekcie głównym, więc nie, Rails nie ma listy modeli.
Ale nadal możesz zajrzeć do zawartości katalogu modeli aplikacji ...
EDYCJA: Innym (dzikim) pomysłem byłoby użycie refleksji Ruby do wyszukiwania wszystkich klas rozszerzających ActiveRecord :: Base. Nie wiem jednak, jak wymienić wszystkie klasy ...
EDYCJA: Dla zabawy znalazłem sposób, aby wymienić wszystkie klasy
EDYCJA: W końcu udało się wymienić wszystkie modele bez patrzenia na katalogi
Jeśli chcesz również obsługiwać klasę pochodną, musisz przetestować cały łańcuch nadklasy. Zrobiłem to, dodając metodę do klasy Class:
źródło
RAILS_ROOT
nie jest już dostępny w Rails 3. Zamiast tego użyjDir.glob(Rails.root.join('app/models/*'))
ActiveRecord::Base
teraz, więc jeśli chcesz załadować wszystkie modele, możesz je łatwo iterować - zobacz moją odpowiedź poniżej.Cała odpowiedź dla szyn 3, 4 i 5 brzmi:
Jeśli
cache_classes
jest wyłączone (domyślnie jest wyłączone w fazie rozwoju, ale włączone w produkcji):Następnie:
Dzięki temu wszystkie modele w aplikacji, niezależnie od tego, gdzie się znajdują, są załadowane, a wszystkie używane klejnoty, które udostępniają modele, są również ładowane.
Powinno to również działać na klasach, które dziedziczą
ActiveRecord::Base
, jakApplicationRecord
w Railsach 5, i zwracają tylko to poddrzewo potomków:Jeśli chcesz dowiedzieć się więcej o tym, jak to zrobić, sprawdź ActiveSupport :: DescendantsTracker .
źródło
:environment
dlaeager_load!
do pracy.Rails.application.eager_load!
, możesz po prostu załadować modele:Dir.glob(Rails.root.join('app/models/*')).each do |x| require x end
Rails.paths["app/models"].existent
katalogi. Chętne ładowanie całej aplikacji jest bardziej kompletną odpowiedzią i upewni się, że absolutnie nie ma już nic do zdefiniowania modeli.Rails.application.paths["app/models"].eager_load!
Na wypadek, gdyby ktoś natknął się na to, mam inne rozwiązanie, nie polegając na czytaniu reżimu ani rozszerzaniu klasy Class ...
Zwróci to tablicę klas. Więc możesz to zrobić
źródło
ActiveRecord::Base.subclasses
ale musisz używaćsend
? Wygląda też na to, że musisz „dotknąć” modelu, zanim się pojawi, na przykładc = Category.new
i się pojawi. W przeciwnym razie nie będzie.ActiveRecord::Base.descendants
ActiveRecord::Base.descendants
je wypisze.wróci
Informacje dodatkowe Jeśli chcesz wywołać metodę na nazwie obiektu bez modelu: ciąg znaków nieznana metoda lub błędy zmiennych, użyj tego
źródło
ActiveRecord::Base.send :subclasses
- szukanie nazw tabel jest dobrym pomysłem. Automatyczne generowanie nazw modeli może być problematyczne, jak wspomniano w lorefnon..capitalize.singularize.camelize
można zastąpić.classify
.Szukałem sposobów na zrobienie tego i ostatecznie wybrałem ten sposób:
źródło: http://portfo.li/rails/348561-how-can-one-list-all-database-tables-from-one-project
źródło
ActiveRecord::Base.connection.tables.each{|t| begin puts "%s: %d" % [t.humanize, t.classify.constantize.count] rescue nil end}
Niektóre modele mogą nie zostać aktywowane, dlatego musisz je uratować.model_classes = ActiveRecord::Base.connection.tables.collect{|t| t.classify.constantize rescue nil }.compact
Dla Rails5 modeli są teraz podklas stanowi
ApplicationRecord
więc do listy wszystkich modeli w swojej aplikacji dostaniesz:Lub krócej:
Jeśli jesteś w trybie deweloperskim, będziesz musiał chętnie ładować modele przed:
źródło
Myślę, że rozwiązanie @ hnovick jest fajne, jeśli nie masz modeli bez tabel. To rozwiązanie działałoby również w trybie programistycznym
Moje podejście jest jednak nieco inne -
klasyfikować jest dobrze podobno daje nazwę klasy z ciągiem prawidłowo . safe_constantize zapewnia, że możesz bezpiecznie przekształcić go w klasę bez zgłaszania wyjątku. Jest to potrzebne, jeśli masz tabele bazy danych, które nie są modelami. kompaktować, aby wszystkie wartości zerowe w wyliczeniu zostały usunięte.
źródło
safe_constantize
.Jeśli chcesz tylko nazwy klas:
Po prostu uruchom go w konsoli Rails, nic więcej. Powodzenia!
EDYCJA: @ sj26 ma rację, musisz uruchomić to zanim zaczniesz dzwonić do potomków:
źródło
map
zputs
? Nie rozumiem o co chodziActiveRecord::Base.descendants.map(&:model_name)
Wydaje mi się, że to działa:
Railsy ładują modele tylko wtedy, gdy są używane, więc linia Dir.glob „wymaga” wszystkich plików w katalogu modeli.
Po umieszczeniu modeli w tablicy możesz zrobić to, o czym myślisz (np. W widoku kodu):
źródło
...'/app/models/**/*.rb'
W jednej linii:
Dir['app/models/\*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }
źródło
Dir['**/models/**/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }
ActiveRecord::Base.connection.tables
źródło
W jednej linii:
źródło
Rails.application.eager_load!
przed wykonaniem w trybie programowania.Nie mogę jeszcze komentować, ale myślę, że odpowiedź sj26 powinna być najwyższą odpowiedzią. Tylko wskazówka:
źródło
Z szynami 6 , Zetiwerk stał się ładowarka domyślny kod.
Aby szybko załadować, spróbuj:
Następnie
źródło
Tak, istnieje wiele sposobów na znalezienie wszystkich nazw modeli, ale to, co zrobiłem w moim klejnotu model_info , daje ci wszystkie modele zawarte nawet w klejnotach.
następnie po prostu wydrukuj to
źródło
Działa to z Railsami 3.2.18
źródło
Aby uniknąć wstępnego ładowania wszystkich Railsów, możesz to zrobić:
Wymagana_zależność (f) jest taka sama
Rails.application.eager_load!
używa. Powinno to uniknąć już wymaganych błędów plików.Następnie możesz użyć wszelkiego rodzaju rozwiązań do listy modeli AR, takich jak
ActiveRecord::Base.descendants
źródło
źródło
Oto rozwiązanie, które zostało sprawdzone dzięki złożonej aplikacji Rails (tej, która napędza Square)
Pobiera najlepsze części odpowiedzi w tym wątku i łączy je w najprostsze i najdokładniejsze rozwiązanie. To obsługuje przypadki, w których twoje modele znajdują się w podkatalogach, użyj set_table_name itp.
źródło
Właśnie natknąłem się na ten, ponieważ muszę wydrukować wszystkie modele z ich atrybutami (zbudowane na komentarzu @Aditya Sanghi):
źródło
To zadziałało dla mnie. Specjalne podziękowania dla wszystkich powyższych postów. Powinno to zwrócić kolekcję wszystkich twoich modeli.
źródło
Do
Rails
realizuje sposóbdescendants
, ale modele niekoniecznie zawsze dziedziczy odActiveRecord::Base
, na przykład, klasy, która zawiera modułActiveModel::Model
będzie miał takie samo zachowanie jako model, po prostu nie będzie powiązana z tabelą.Uzupełniając to, co mówią koledzy powyżej, najmniejszy wysiłek przyniesie to:
Łatka Małpy klasy
Class
Ruby:oraz metodę
models
, w tym przodków, ponieważ:Metoda
Module.constants
zwraca (powierzchownie) kolekcjęsymbols
zamiast stałych, więc metodęArray#select
można zastąpić tak jak ta łatka małpyModule
:Łatka małpy
String
.I wreszcie metoda modeli
źródło
To da ci wszystkie klasy modeli, które masz w swoim projekcie.
źródło
źródło
Próbowałem wielu z tych odpowiedzi bezskutecznie w Rails 4 (wow, zmienili jedną lub dwie rzeczy na litość boską) postanowiłem dodać własną. Te, które wywołały ActiveRecord :: Base.connection i wyciągnęły nazwy tabel, działały, ale nie uzyskały pożądanego rezultatu, ponieważ ukryłem niektóre modele (w folderze wewnątrz aplikacji / models /), których nie chciałem usunąć:
Umieszczam to w inicjalizatorze i mogę wywoływać to z dowolnego miejsca. Zapobiega niepotrzebnemu użyciu myszy.
źródło
mogę to sprawdzić
źródło
Zakładając, że wszystkie modele są w aplikacji / modelach i masz grep i awk na swoim serwerze (większość przypadków),
Jest to szybsze niż
Rails.application.eager_load!
lub zapętlanie każdego pliku za pomocąDir
.EDYTOWAĆ:
Wadą tej metody jest brak modeli, które pośrednio dziedziczą z ActiveRecord (np
FictionalBook < Book
.). Najpewniejszym sposobem jest toRails.application.eager_load!; ActiveRecord::Base.descendants.map(&:name)
, że jest trochę powolne.źródło
Rzucam ten przykład tutaj, jeśli ktoś uzna to za przydatne. Rozwiązanie oparte jest na tej odpowiedzi https://stackoverflow.com/a/10712838/473040 .
Powiedzmy, że masz kolumnę
public_uid
, który jest używany jako podstawowy identyfikator światem zewnętrznym (można findjreasons dlaczego chciał to zrobić tutaj )Powiedzmy teraz, że wprowadziłeś to pole do wielu istniejących modeli i teraz chcesz zregenerować wszystkie rekordy, które nie zostały jeszcze ustawione. Możesz to zrobić w ten sposób
możesz teraz biegać
rake di:public_uids:generate
źródło