2012-09-18 29 views
5

Tôi có một mô hình lớp Rails với một thuộc tính Hash đăng, như thế này:ActiveRecord chuyển đổi phím biểu tượng thành các chuỗi khi tuần tự băm của tôi

class Action 
    serialize :metadata, Hash 
    # . . . 
end 

cột đó được lưu trữ trong một cột text với một mã hóa YAML. Vấn đề là khi tôi chuyển giá trị metadata cho phương thức create!, các khóa băm được chuyển đổi từ các biểu tượng thành chuỗi, nhưng chuyển đổi đó không xảy ra vào các thời điểm khác. Ví dụ:

$ rails console 
> a = Action.create!(:metadata => {:foo => "bar"}) 
> a.metadata 
=> {"foo"=>"bar"} 
> a.metadata[:fizz] = "buzz" 
> a.metadata 
=> {"foo"=>"bar", :fizz=>"buzz"} 

Bây giờ khi tôi lưu các mô hình, cơ sở dữ liệu sẽ có giá trị văn bản này:

--- 
foo: bar 
:fizz: buzz 

Bất kỳ lời đề nghị làm thế nào để sửa lỗi này?

(Đây là với Rails 3.0.16.)

+0

Liệu nó biểu hiện giống nhau hành vi với 'serialize: metadata, HashWithIndifferentAccess'? – gregates

+1

@gregates: Tôi đã thử nó, và nó có nghĩa là tôi có thể truy vấn băm bằng chuỗi hoặc ký hiệu và nhận giá trị, nhưng có hai vấn đề: 'Action.create! (: Metadata => {: foo =>: bar}) 'đặt ra một ngoại lệ vì tôi không được phép chuyển một Hash thuần túy nữa, và' Action.find (an_old_id) 'tăng một ngoại lệ SerializationTypeMismatch vì Rails không biết cách chuyển đổi YAML thành một HashWithIndifferentAccess. –

Trả lời

3

Đi trả lời này bản thân mình, với một biến thể của @ đề nghị Mori:

class Action < ActiveRecord::Base 
    def metadata=(v) 
    self[:metadata] = v.try(:symbolize_keys!) 
    end 
end 

Theo như tôi có thể nói, đây làm việc xung quanh vấn đề mà không vi phạm giao diện ở nơi khác. Tôi đoán nếu tôi muốn một chìa khóa để là một chuỗi, phương pháp này sẽ khiến tôi ngạc nhiên khó chịu, nhưng đó không phải là trường hợp, vì vậy tôi sẵn sàng chấp nhận nó hơn những bất ngờ được đưa ra bởi các giải pháp được đề xuất khác.

Btw, nếu ai đó có thể đề xuất giải pháp không yêu cầu loại giải pháp này, tôi sẽ vui lòng chấp nhận câu trả lời đúng đó thay thế.

2
class Action < ActiveRecord::Base 
    def metadata 
    self[:metadata].try :symbolize_keys 
    end 
end 
+1

Đây là một gợi ý hay, nhưng bây giờ nếu tôi nói 'a.metadata [: foo] = 'bar'' thay đổi bị mất, bởi vì tôi đang gán cho một bản sao của băm chứ không phải là băm được tham chiếu bởi mô hình. –

+0

. . . Nhưng, nó * làm * nếu tôi thay vào đó nói 'self [: metadata] .ryry: symbolize_keys!'. Mặc dù vậy, cảm giác đó sai. –

0

Tôi đã kết thúc bằng một tuyến đường khác. Tôi chắc chắn rằng tôi có được một trở HashWithIndifferentAccess khi tôi truy cập vào thuộc tính:

def metadata 
    return self[:metadata] if self[:metadata].is_a?(HashWithIndifferentAccess) 
    self[:metadata] = HashWithIndifferentAccess.new(self[:metadata]) 
end 

Một thêm tiền thưởng cho điều này là nếu metadata không được thiết lập tôi nhận được một băm rỗng trở lại thay vì nil

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