ruby konwertuje nazwę klasy w łańcuchu na aktualną klasę

87

Jak wywołać klasę z łańcucha zawierającego nazwę klasy w środku? (Myślę, że mógłbym zrobić przypadek / kiedy, ale to wydaje się brzydkie.)

Pytam, ponieważ używam acts_as_commentablemiędzy innymi wtyczki i przechowują one parametr commentable_type jako kolumnę. Chcę móc przywołać jakąkolwiek klasę, którą można komentować, aby to zrobiła find(commentable_id).

Dzięki.

nieposortowany
źródło

Odpowiedzi:

131

Myślę, że chcesz constantize

To jest konstrukcja RoR. Nie wiem, czy jest jeden na rdzeń rubinowy

Jamie Wong
źródło
idealnie, właśnie tego szukałem.
nieposortowane
40
W przypadku zwykłego Rubiego użyłbyś Module.const_get. Zaletą constantizejest to, że działa nawet z głęboko zagnieżdżonymi przestrzeniami nazw, więc możesz zrobić 'Functional::Collections::LazyList'.constantizei pobrać klasę LazyList z modułu Kolekcje w module Functional, podczas gdy z const_get, musisz zrobić coś podobnego 'Functional::Collections::LazyList'.split('::').reduce(Module, :const_get).
Chuck
45
"Object".constantize # => Object
jtbandes
źródło
Zwróć uwagę, że .constantizejest to metoda Railsów, nie znajdziesz jej w zwykłym Ruby
Edgar Ortega
35

Biorąc pod uwagę łańcuch, najpierw wywołaj classify, aby utworzyć nazwę klasy (nadal ciąg), a następnie wywołaj constantize, aby spróbować znaleźć i zwrócić stałą nazwy klasy (zwróć uwagę, że nazwy klas są stałymi ).

some_string.classify.constantize
user664833
źródło
10
Powinieneś używać camelize zamiast classify, ponieważ klasyfikacja jest przeznaczona dla nazw tabel i nie obsługuje zbyt dobrze liczby mnogiej.
Peter Brown,
1
Dzięki! to wspaniale!
duykhoa
2
Twoja odpowiedź jest naprawdę cenna, ale powinieneś użyć "titleize" dla nazwy tabeli zawierającej spacje i usunąć spacje z ciągu, aby nadać znaczenie pełnej nazwie klasy.
SSR
22

Wiem, że to stare pytanie, ale chcę tylko zostawić tę notatkę, może być pomocna dla innych.

W zwykłym Rubim Module.const_getmożna znaleźć zagnieżdżone stałe. Na przykład o następującej strukturze:

module MyModule
  module MySubmodule
    class MyModel
    end
  end
end

Możesz go użyć w następujący sposób:

Module.const_get("MyModule::MySubmodule::MyModel")
MyModule.const_get("MySubmodule")
MyModule::MySubmodule.const_get("MyModel")
Edgar Ortega
źródło
7

Kiedy ActiveSupport jest dostępne (np. W Railsach): String#constantizelub String#safe_constantize, to znaczy "ClassName".constantize.

W czystym Ruby:, Module#const_getzazwyczaj Object.const_get("ClassName").

W ostatnich rubinach oba działają ze stałymi zagnieżdżonymi w modułach, na przykład w Object.const_get("Outer::Inner").

skalee
źródło
6

Jeśli chcesz przekonwertować ciąg na rzeczywistą nazwę klasy, aby uzyskać dostęp do modelu lub dowolnej innej klasy

str = "group class"

> str.camelize.constantize 'or'
> str.classify.constantize 'or'
> str.titleize.constantize

Example :
  def call_me(str)
    str.titleize.gsub(" ","").constantize.all
  end

Call method : call_me("group class")

Result:
  GroupClass Load (0.7ms) SELECT `group_classes`.* FROM `group_classes`
SSR
źródło