2012-09-25 7 views
21

Próbuję ustawić kilka zmiennych klasy do przechowywania ścieżki w aplikacji Rails (ale myślę, że to bardziej kwestia rubinowy)Jaki jest właściwy sposób dostępu do zmiennych klasowych w Rubim 1.9?

Zasadniczo moja klasa wygląda to

class Image < ActiveRecord::Base 

    @@path_to_folder = "app/assets" 
    @@images_folder = "upimages" 
    @@path_to_images = File.join(@@path_to_folder, @@images_folder) 

end 

Ale gdy próbuję Dostęp @@path_to_images z mojego kontrolera wykonując Image.path_to_images, dostaję NoMethodError

Kiedy próbuję z Image.class_eval(@@path_to_images), dostaję uninitialized class variable @@path_to_images in ImagesController

Rozglądałem się dookoła i wszystko widziałem mówi ci będzie działać, więc jestem bardzo pomylić o tym

Co więcej, próbowałem definiowanie prostych zajęcia z konsolą ruby ​​jak tak

class Bidule 
    @@foo = "foo" 
    Bar = "bar" 
end 

Tak więc próbowałem, jak sądzę, wszystkie możliwe sposoby (poprzednie 2), aby uzyskać do nich dostęp, ale nie zawsze otrzymuję wyjątek podniesiony

+2

dlaczego nie klasy stałe? potrzebujesz akcesorów ('cattr_accessor'), aby uzyskać dostęp do zmiennych klas od zewnątrz. http://apidock.com/rails/Class/cattr_accessor – tokland

Odpowiedz

24

Szyny zapewnia poziomie klasy atrybutu akcesor dla tej funkcjonalności

Spróbuj

class Image < ActiveRecord::Base 
    cattr_accessor :path_to_folder 
    @@path_to_folder = "app/assets" 
end 

Wtedy dostęp do zmiennej klasy path_to_folder wystarczy użyć

Image.path_to_folder 

Ale ludzie zawsze sugerują, aby uniknąć zmiennych klasie dzięki jego zachowanie w dziedziczeniu. Można użyć stałych takich jak

class Image < ActiveRecord::Base 
    PATH_TO_FOLDER = "app/assets" 
end 

Następnie można uzyskać dostęp do stałej jak

Image::PATH_TO_FOLDER 
2

Zmienne klas są rzadko używane w aplikacjach Ruby, ponieważ mają wiele ograniczeń, a także mają tendencję do działania wbrew konkretnemu projektowi zorientowanemu na obiekt.

W niemal każdym przypadku zmienna klasy może być zastąpiona odpowiednią stałą, klasą lub obydwoma.

Twój przykład jest prawdopodobnie lepiej opisane jako:

class Image < ActiveRecord::Base 
    PATH_TO_FOLDER = "app/assets" 
    IMAGES_FOLDER = "upimages" 
    PATH_TO_IMAGES = File.join(PATH_TO_FOLDER, IMAGES_FOLDER) 
end 

zmienne klasy są prywatne do danej klasy i nie dotarły do ​​podklasy i są trudno dostępne z kontekstu zewnętrznego. Używanie stałych pozwala na korzystanie z rzeczy, takich jak:

image_path = Image::PATH_TO_FOLDER 

Istnieją pewne okoliczności, w których zmienna klasa jest bardziej uzasadnione niż alternatywa, ale są to zazwyczaj bardzo rzadkie.

+0

Obie odpowiedzi są naprawdę dobre, dziękuję, mogę tylko sprawdzić jedno :( –

9

Chociaż nie będę w ogóle go polecam, można uzyskać dostęp do zmiennych klasy przekazując ciąg do class_eval jak w:

Image.class_eval('@@path_to_folder') 

przynajmniej w późniejszych wersjach Rubiego.

Należy jednak zauważyć, że zmienne klasy są powiązane z najwyższą klasą w hierarchii z podklasą. W przypadku podklas ActiveRecord, takich jak ta, oznacza to, że te zmienne klasowe istnieją w przestrzeni nazw ActiveRecord::Base.

+1

brzydki, ale wykonuje pracę, dzięki! – akostadinov

1

Można to zrobić poprzez owinięcie go w metodzie klasy tak:

def self.path_to_images 
    @@path_to_images 
end 

ale należy wspomnieć, że należy starać się unikać zmiennych klasy w szynach

3

Jeśli nie możesz lub nie chcą rozszerzyć stosowanie klasa:

Image.class_variable_get(:@@path_to_images) 
1

chciałbym zmodyfikować go tak:

class Image < ActiveRecord::Base 

    @@path_to_folder = "app/assets" 
    @@images_folder = "upimages" 
    @@path_to_images = File.join(@@path_to_folder, @@images_folder) 

    def initialize 
    end 
    ... 
    def self.path_to_folder 
    @@path_to_folder 
    end 
end 

To, co tutaj zrobiliście, powoduje, że zmienna klasy staje się metodą, więc teraz można uzyskać dostęp za pomocą wywołania metody .method. Ponieważ jest to jednak zmienna klasy, można ją wywołać tylko na samej klasie, a nie na instancji klasy. Otrzymujesz "NoMethodError", ponieważ wywołujesz zmienną klasy przy użyciu metody, która nie istnieje. Powyższy kod definiuje tę metodę na liniach gdzie słownie:

def self.path_to_folder 
    @@path_to_folder 
end 

To będzie teraz działać:

Image.path_to_folder 
2

Najlepszym sposobem jest ustawienie i uzyskać wartość przy użyciu metod. Poniżej znajduje się przykładowy kod

class Planet 
    @@planets_count = 0 

    def initialize(name) 
    @name = name 
    @@planets_count += 1 
    end 

    def self.planets_count 
    @@planets_count 
    end 

    def self.add_planet 
    @@planets_count += 1 
    end 

    def add_planet_from_obj 
    @@planets_count += 1 
    end 
end 


Planet.new("uranus") 
Plant.add_planet 
obj = Planet.new("earth") 
obj.add_planet_from_obj 
Powiązane problemy