繁体   English   中英

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

[英]What is the proper way to access class variables in Ruby 1.9?

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

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

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个)来访问它们,但我总是得到一个例外

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

尝试

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

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

Image.path_to_folder

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM