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

时间:2012-09-25 20:43:15

标签: ruby-on-rails ruby

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

基本上我的课看起来像这样

class Image < ActiveRecord::Base

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

end

但是当我尝试通过执行@@path_to_images从我的控制器访问Image.path_to_images时,我得到NoM​​ethodError

当我尝试Image.class_eval( @@path_to_images )时,我得到uninitialized class variable @@path_to_images in ImagesController

我已经四处搜寻了,我所看到的一切都说会有用,所以我对此感到很困惑

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

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

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

7 个答案:

答案 0 :(得分:24)

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

答案 1 :(得分:9)

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

Image.class_eval('@@path_to_folder')

至少在Ruby的后期版本中。

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

答案 2 :(得分:3)

如果你不能或不想扩展课堂使用:

Image.class_variable_get(:@@path_to_images)

答案 3 :(得分:2)

类变量在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

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

def self.path_to_images
  @@path_to_images
end

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

答案 6 :(得分:1)

我会像这样修改它:

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名称调用进行访问。因为这是一个类变量,所以你只能在类本身上调用它,而不能在类的实例上调用它。 你得到了一个N​​oMethodError&#39;因为您使用不存在的方法调用类变量。上面的代码在你说的行上定义了这个方法:

def self.path_to_folder
  @@path_to_folder
end

现在可以使用:

Image.path_to_folder