2012-05-17 30 views

Trả lời

-2

Tôi khuyên bạn nên thêm phương thức tùy chỉnh to_yaml vào lớp học của bạn để xây dựng định dạng yaml cụ thể mà bạn muốn.

Tôi biết rằng to_json chấp nhận tham số để cho biết thuộc tính nào cần tuần tự hóa, nhưng tôi không thể tìm thấy các thuộc tính cho to_yaml.

Đây là nguồn thực tế cho to_yaml:

# File activerecord/lib/active_record/base.rb, line 653 

    def to_yaml(opts = {}) #:nodoc: 
    if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? 
     super 
    else 
     coder = {} 
     encode_with(coder) 
     YAML.quick_emit(self, opts) do |out| 
     out.map(taguri, to_yaml_style) do |map| 
      coder.each { |k, v| map.add(k, v) } 
     end 
     end 
    end 
    end 

Vì vậy, có vẻ như có thể là một cơ hội để thiết opts để nó bao gồm cặp khóa/giá trị cụ thể trong yaml.

8

Sau khi một số tiền inordinate tìm kiếm tôi loạng choạng về điều này:

class Point 
    def to_yaml_properties 
    ["@x", "@y"] 
    end 
end 

Phương pháp này được sử dụng để chọn các thuộc tính mà YAML serializes. Có một cách tiếp cận mạnh mẽ hơn liên quan đến các trình phát tùy chỉnh (trong Psych) nhưng tôi không biết nó là gì.

Giải pháp này chỉ hoạt động trong Ruby 1.8; trong Ruby 1.9, to_yaml đã chuyển sang sử dụng Psych, mà câu trả lời của Matt sử dụng encode_with là giải pháp thích hợp.

22

Trong Ruby 1.9, to_yaml_properties is deprecated; nếu bạn đang sử dụng của Ruby 1.9, một phương pháp chứng minh trong tương lai hơn là nên sử dụng encode_with:

class Point 
    def encode_with coder 
    coder['x'] = @x 
    coder['y'] = @y 
    end 
end 

Trong trường hợp này đó là tất cả bạn cần, vì mặc định là để thiết lập các biến dụ tương ứng của đối tượng mới đến giá trị thích hợp khi tải từ YAML, nhưng trong trường hợp comple hơn bạn có thể sử dụng init_with:

def init_with coder 
    @x = coder['x'] 
    @y = coder['y'] 
end 
+0

FYI: Nếu bạn ghi đè lên '# init_with' cho một 'ActiveRecord :: Base' lớp con, hãy nhớ quay trở lại' self', nếu không bất cứ lúc nào bạn khởi tạo một mô hình nó sẽ trở lại nil. – siannopollo

1

Nếu bạn muốn tất cả các lĩnh vực nhưng một số ít, bạn có thể làm điều này

def encode_with(coder) 
    vars = instance_variables.map{|x| x.to_s} 
    vars = vars - ['@unwanted_field1', '@unwanted_field2'] 

    vars.each do |var| 
    var_val = eval(var) 
    coder[var.gsub('@', '')] = var_val 
    end 
end 

Điều này ngăn bạn khỏi phải tự quản lý danh sách. Thử nghiệm trên Ruby 1,9

1

Nếu bạn có một nhiều của các biến Ví dụ, bạn có thể sử dụng một phiên bản ngắn như thế này một

def encode_with(coder) 
    %w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "@#{v}" } 
end 
0

Bạn nên sử dụng #encode_with vì #to_yaml_properties bị phản đối:

def encode_with(coder) 
    # remove @unwanted and @other_unwanted variable from the dump 
    (instance_variables - [:@unwanted, :@other_unwanted]).each do |var| 
    var = var.to_s      # convert symbol to string 
    coder[var.gsub('@', '')] = eval(var) # set key and value in coder hash 
    end 
end 

hoặc bạn có thể thích điều này nếu eval quá nguy hiểm và bạn chỉ cần lọc ra một biến thể hiện. Tất cả vars khác cần phải có một accessor:

attr_accessor :keep_this, :unwanted 

def encode_with(coder) 
    # reject @unwanted var, all others need to have an accessor 
    instance_variables.reject{|x|x==:@unwanted}.map(&:to_s).each do |var| 
    coder[var[1..-1]] = send(var[1..-1]) 
    end 
end 
+0

Thêm một số nhận xét vào câu trả lời của bạn. – HDJEMAI

Các vấn đề liên quan