2012-09-25 13 views
21

estoy tratando de establecer algunas variables de clase para almacenar caminos en una aplicación Rails (pero creo que esto más bien una cuestión de rubí)¿Cuál es la forma correcta de acceder a las variables de clase en Ruby 1.9?

Básicamente mi clase tiene este aspecto

class Image < ActiveRecord::Base 

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

end 

Pero cuando intento acceso @@path_to_images de mi controlador haciendo Image.path_to_images, consigo un NoMethodError

Cuando trato con Image.class_eval(@@path_to_images), consigo uninitialized class variable @@path_to_images in ImagesController

He buscado alrededor y todo lo que he visto dice que los quiere trabajar, así que estoy muy confundido acerca de este

Lo que es más, he intentado definir clases simples con la consola de rubí como tal

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

Y así que intenté, creo, todas las formas posibles (las anteriores 2 incluidas) para acceder a ellas, pero de ninguna manera siempre aparece una excepción.

+2

¿por qué no las constantes de clase? necesita accesodores ('cattr_accessor') para acceder a variables de clase desde el exterior. http://apidock.com/rails/Class/cattr_accessor – tokland

Respuesta

24

rieles proporciona nivel de clase de atributo de acceso para esta funcionalidad

Trate

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

luego para acceder variable de clase path_to_folder sólo tiene que utilizar

Image.path_to_folder 

Pero la gente siempre sugieren para evitar las variables de clase debido a las su comportamiento en herencia. Así que puede usar constantes como

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

luego podrás acceder a la constante como

Image::PATH_TO_FOLDER 
2

Las variables de clase rara vez se utilizan en las aplicaciones de Ruby porque tienen muchas limitaciones y también tienden a correr a contrapelo del diseño orientado a objetos adecuado.

En casi todos los casos, una variable de clase se puede reemplazar con una constante adecuada, un método de clase o ambos.

Su ejemplo es probablemente mejor descrito como:

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

Las variables de clase son privados para la clase en cuestión y no alcancen a los sub-clases y son difíciles de acceder desde un contexto externo. El uso de constantes permite el uso de cosas como:

image_path = Image::PATH_TO_FOLDER 

Hay algunas circunstancias en las que una variable de clase es más razonable que la alternativa, pero por lo general son muy raros.

+0

Ambas respuestas son realmente buenas, gracias, solo puedo marcar una :( –

9

Aunque yo no lo recomiendo en general, se puede acceder a las variables de clase al pasar una cadena a class_eval como en:

Image.class_eval('@@path_to_folder') 

al menos en versiones posteriores de Ruby.

Tenga en cuenta, sin embargo, que las variables de clase están asociadas a la clase superior en una jerarquía subclasificada. En el caso de las subclases de ActiveRecord como esta, esto significa que estas variables de clase realmente existen en el espacio de nombres de ActiveRecord::Base.

+1

feo pero cumple su función, ¡gracias! – akostadinov

1

Puede hacerlo envolviéndolo en un método de clase, así:

def self.path_to_images 
    @@path_to_images 
end 

pero debo mencionar que usted debe tratar de evitar el uso de variables de clase en los carriles

3

Si no puede o no quieren extender su uso en clase:

Image.class_variable_get(:@@path_to_images) 
1

me habría modificarlo así:

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 

Lo que ha hecho aquí es convertir la variable de clase en un método, por lo que ahora puede acceder utilizando una llamada de nombre de método. Sin embargo, como se trata de una variable de clase, solo puede invocar esto en la clase en sí, no en la instancia de una clase. Obtendrá un 'NoMethodError' porque está llamando a la variable de clase utilizando un método que no existe. El código anterior define este método en las líneas en el que dice:

def self.path_to_folder 
    @@path_to_folder 
end 

Esto ahora funcionará:

Image.path_to_folder 
2

mejor forma de hacerlo es establecer y obtener el valor utilizando métodos. A continuación se muestra un código de muestra

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 
Cuestiones relacionadas