2012-09-25 25 views
21

Tôi đang cố gắng để thiết lập một số biến lớp học để lưu trữ đường dẫn trong một ứng dụng Rails (nhưng tôi nghĩ rằng đây là một câu hỏi hơn ruby)Cách thích hợp để truy cập các biến lớp trong Ruby 1.9 là gì?

Về cơ bản lớp học của tôi trông như thế này

class Image < ActiveRecord::Base 

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

end 

Nhưng khi tôi cố gắng truy cập @@path_to_images từ bộ điều khiển của tôi bằng cách làm Image.path_to_images, tôi nhận được một NoMethodError

Khi tôi cố gắng với Image.class_eval(@@path_to_images), tôi nhận được uninitialized class variable @@path_to_images in ImagesController

Tôi đã tìm kiếm xung quanh và tất cả những gì đã nhìn thấy nói những người sẽ làm việc, vì vậy tôi rất bối rối về vấn đề này

Hơn thế nữa, tôi đã cố gắng xác định các lớp học đơn giản với giao diện điều khiển ruby ​​như vậy

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

Và vì vậy tôi đã thử, tôi nghĩ, tất cả các cách có thể (bao gồm 2 trước đó) để truy cập chúng nhưng không có cách nào tôi luôn có ngoại lệ được nêu ra

+2

tại sao không phải là hằng số lớp? bạn cần accessors ('cattr_accessor') để truy cập các biến lớp từ bên ngoài. http://apidock.com/rails/Class/cattr_accessor – tokland

Trả lời

24

Rails cung cấp accessor thuộc tính cấp độ lớp cho chức năng này

Hãy thử

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

Sau đó, để truy cập biến lớp path_to_folder chỉ cần sử dụng

Image.path_to_folder 

Nhưng mọi người luôn đề nghị để tránh các biến lớp do hành vi của nó trong inheritance.So bạn có thể sử dụng các hằng số như

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

Sau đó, bạn có thể truy cập liên tục như

Image::PATH_TO_FOLDER 
2

Biến lớp hiếm khi được sử dụng trong các ứng dụng Ruby vì chúng có nhiều hạn chế và có xu hướng chạy chống lại hạt thiết kế hướng đối tượng thích hợp.

Trong hầu hết các trường hợp, một biến lớp có thể được thay thế bằng một hằng số thích hợp, một phương thức lớp hoặc cả hai.

dụ của bạn có lẽ tốt hơn được mô tả như sau:

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

biến Class là tới lớp trong câu hỏi và không chảy xuống đến tiểu học và rất khó để truy cập từ một bối cảnh bên ngoài. Sử dụng các hằng số cho phép sử dụng những thứ như:

image_path = Image::PATH_TO_FOLDER 

Có một số trường hợp mà biến lớp hợp lý hơn thay thế, nhưng điều này thường rất hiếm.

+0

Cả hai câu trả lời đều thực sự tốt cảm ơn bạn, tôi chỉ có thể kiểm tra một tuy nhiên: ( –

9

Mặc dù tôi sẽ không nói chung giới thiệu nó, bạn có thể truy cập các biến lớp học bằng cách đi qua một chuỗi để class_eval như trong:

Image.class_eval('@@path_to_folder') 

ít nhất là trong các phiên bản sau của Ruby.

Lưu ý, tuy nhiên, các biến lớp được liên kết với lớp trên cùng trong phân cấp được phân lớp. Trong trường hợp của các lớp con ActiveRecord như thế này, điều này có nghĩa là các biến lớp thực sự tồn tại trong không gian tên là ActiveRecord::Base.

+1

xấu xí nhưng thực hiện công việc, cảm ơn! – akostadinov

1

Bạn có thể làm điều đó bằng cách gói nó trong một phương pháp học, như thế này:

def self.path_to_images 
    @@path_to_images 
end 

nhưng tôi nên đề cập đến mà bạn nên cố gắng tránh sử dụng các biến lớp trong đường ray

3

If you can not hoặc không muốn mở rộng sử dụng lớp:

Image.class_variable_get(:@@path_to_images) 
1

tôi sẽ sửa đổi nó như thế này:

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 

Những gì bạn đã thực hiện ở đây là biến biến lớp thành một phương thức, vì vậy bây giờ bạn có thể truy cập đang sử dụng lệnh gọi .method. Vì đây là một biến lớp mặc dù, bạn chỉ có thể gọi nó trên chính lớp đó, chứ không phải trên cá thể của một lớp. Bạn đang nhận được một 'NoMethodError' vì bạn đang gọi biến lớp bằng cách sử dụng một phương thức chưa tồn tại. Đoạn mã trên định nghĩa phương pháp này trên dòng mà bạn nói:

def self.path_to_folder 
    @@path_to_folder 
end 

này bây giờ sẽ làm việc:

Image.path_to_folder 
2

Cách tốt nhất là để thiết lập và nhận được giá trị sử dụng phương pháp này. Bên dưới là mã mẫu

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 
Các vấn đề liên quan