在Ruby 1.9中访问类变量的正确方法是什么?

我正在尝试设置一些类变量来存储Rails应用程序中的路径(但我认为这更像是一个ruby问题)

基本上我的class级看起来像这样

class Image < ActiveRecord::Base @@path_to_folder = "app/assets" @@images_folder = "upimages" @@path_to_images = File.join(@@path_to_folder, @@images_folder) end 

但是当我尝试通过执行Image.path_to_images从我的控制器访问@@path_to_images ,我得到一个NoMethodError

当我尝试使用Image.class_eval( @@path_to_images ) ,我uninitialized class variable @@path_to_images in ImagesController获得了uninitialized class variable @@path_to_images in ImagesController

我四处搜索,我所看到的一切都说会有用,所以我对此非常困惑

更重要的是,我尝试使用ruby控制台来定义简单类

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

所以,我认为,我尝试了所有可能的方式(包括前2个)来访问它们,但我总是不会提出exception

Rails为此function提供类级别属性访问器

尝试

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

然后访问path_to_folder类变量就可以了

 Image.path_to_folder 

但人们总是建议避免类变量,因为它在inheritance中的行为。所以你可以使用像常量这样的常量

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

然后你就可以访问常量了

 Image::PATH_TO_FOLDER 

虽然我一般不会推荐它,但您可以通过将字符串传递给class_eval来访问类变量,如下所示:

 Image.class_eval('@@path_to_folder') 

至少在Ruby的更高版本中。

但请注意,类变量与子类层次结构中最高级的类相关联。 对于像这样的ActiveRecord子类,这意味着这些类变量确实存在于ActiveRecord::Base的命名空间中。

如果您不能或不想扩展课程使用:

 Image.class_variable_get(:@@path_to_images) 

类变量在Ruby应用程序中很少使用,因为它们有很多限制,并且往往会违反正确的面向对象设计。

几乎在每种情况下,类变量都可以用适当的常量,类方法或两者替换。

您的示例可能更好地描述为:

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

类变量对于所讨论的类是私有的,并且不会渗透到子类,并且难以从外部上下文访问。 使用常量允许使用如下内容:

 image_path = Image::PATH_TO_FOLDER 

在某些情况下,类变量比替代方案更合理,但这些通常非常罕见。

最好的方法是使用方法设置和获取值。 以下是示例代码

 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 

您可以通过将其包装在类方法中来实现,如下所示:

 def self.path_to_images @@path_to_images end 

但我应该提一下,你应该尽量避免在rails中使用类变量

我会像这样修改它:

 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 

你在这里做的是将类变量变成一个方法,所以你现在可以使用.method名称调用。 因为这是一个类变量,所以你只能在类本身上调用它,而不能在类的实例上调用它。 你得到一个'NoMethodError',因为你使用一个不存在的方法调用类变量。 上面的代码在你说的行上定义了这个方法:

 def self.path_to_folder @@path_to_folder end 

这将现在有效:

 Image.path_to_folder