2008-09-25 12 views

Odpowiedz

87

Żadne z tych rozwiązań nie uwzględnia stałej z wieloma modułami nadrzędnymi. Na przykład:

A::B::C 

Jak szyn 3.2.x można po prostu:

"A::B::C".deconstantize #=> "A::B" 

Jak Rails 3.1.x można:

constant_name = "A::B::C" 
constant_name.gsub("::#{constant_name.demodulize}", '') 

To dlatego #demodulize jest przeciwieństwem #deconstantize:

"A::B::C".demodulize #=> "C" 

Jeśli naprawdę trzeba to zrobić ręcznie, spróbuj tego:

constant_name = "A::B::C" 
constant_name.split('::')[0,constant_name.split('::').length-1] 
+1

To powinna być zaakceptowana odpowiedź. – pdoherty926

+0

To pytanie zostało napisane przed Railsami 3, a moduły nie były tak naprawdę obsługiwane. Zaktualizowana zaakceptowana odpowiedź odzwierciedlająca bardziej aktualne wersje! – Steropes

+1

Demodulize była kluczową odpowiedzią – Donato

21

ten powinien zrobić:

def get_module_name 
    @module_name = self.class.to_s.split("::").first 
    end 
+11

lub U, może również użyć ** self.class.name.demodulize ** dla tego celu. – TiSer

+3

nie, nie można, faktycznie zdemodulować zwraca nazwę klasy bez przestrzeni nazw – Fivell

+2

Jak zauważył Jason Harrelson, nie bierze pod uwagę wielu modułów macierzystych. – roychri

1

nie sądzę jest czystsze sposób, i widziałem to gdzieś indziej

class ApplicationController < ActionController::Base 
    def get_module_name 
    @module_name = self.class.name.split("::").first 
    end 
end 
6

to będzie działać jeśli kontroler ma nazwę modułu, ale zwróci nazwę kontrolera, jeśli nie.

class ApplicationController < ActionController::Base 
    def get_module_name 
    @module_name = self.class.name.split("::").first 
    end 
end 

Jeśli jednak zmienić się trochę do:

class ApplicatioNController < ActionController::Base 
    def get_module_name 
    my_class_name = self.class.name 
    if my_class_name.index("::").nil? then 
     @module_name = nil 
    else 
     @module_name = my_class_name.split("::").first 
    end 
    end 
end 

Można określić, czy klasa ma nazwę modułu, czy nie i wrócić jeszcze coś innego niż nazwa klasy, które można testować dla.

2

Wiem, że to stary wątek, ale właśnie natknąłem się na potrzebę oddzielnej nawigacji w zależności od przestrzeni nazw kontrolera. Rozwiązanie wymyśliłem było to w moim układzie aplikacji:

<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %> 

który wygląda nieco skomplikowany, ale w zasadzie wykonuje następujące - bierze nazwę klasy kontroler, który byłby na przykład „Ludzie” dla nie- kontroler nazwanych pseudonimów i "Admin :: Users" dla nazwy o podanej nazwie. Używając metody łańcuchowej [] z wyrażeniem regularnym, które zwraca cokolwiek przed dwoma dwukropkami lub zero, jeśli nic nie ma. Następnie zmienia się na małe litery ("try" jest tam, na wypadek, gdyby nie istniała przestrzeń nazw, a zwracana jest zero). To pozostawia nam przestrzeń nazw lub zero. Wtedy to po prostu sprawia, że ​​częściowe z lub bez nazw, na przykład nie nazw:

app/views/_nav.html.erb 

lub w przestrzeni nazw admin:

app/views/admin/_nav.html.erb 

Oczywiście te partials musi istnieć dla każdej przestrzeni nazw w przeciwnym razie błędu występuje. Teraz nawigacja dla każdej przestrzeni nazw pojawi się dla każdego kontrolera bez konieczności zmiany kontrolera lub widoku.

1

I polecam gsub zamiast split. Jest bardziej efektywny, ponieważ nie potrzebujesz żadnej innej nazwy modułu.

class ApplicationController < ActionController::Base 
    def get_module_name 
    @module_name = self.class.to_s.gsub(/::.*/, '') 
    end 
end 
2

my_class.name.underscore.split('/').slice(0..-2)

lub

my_class.name.split('::').slice(0..-2)

14

Dla prostego przypadku można użyć:

self.class.parent 
+0

Czy jest dostępna tylko w ostatnich Rubinach? Nie mogę uwierzyć, że jest tak wiele odpowiedzi z "mroczną magią" i nikt nie odwoływał się do tej metody do 2015 roku –

1

Z wielu podmodułów:

module ApplicationHelper 
    def namespace 
    controller.class.name.gsub(/(::)?\w+Controller$/, '') 
    end 
end 

przykład: Foo::Bar::BazController =>Foo::Bar