2009-03-25 51 views
12

Tôi đang bối rối với vấn đề này.Làm thế nào để bạn đối phó với xung đột giữa ActiveSupport :: JSON và đá quý JSON?

ActiveSupport::JSON xác định to_json trên các đối tượng lõi khác nhau và cũng như đá quý JSON. Tuy nhiên, việc thực hiện không giống nhau - phiên bản ActiveSupport có các đối số và phiên bản đá quý JSON không.

Tôi đã cài đặt một đá quý yêu cầu đá quý JSON và ứng dụng của tôi bị hỏng. Vấn đề là tôi đang sử dụng to_json trong một bộ điều khiển trả về một danh sách các đối tượng, nhưng tôi muốn kiểm soát các thuộc tính được trả về.

Khi mã bất cứ nơi nào trong hệ thống của tôi không require 'json' tôi nhận được thông báo lỗi này:

TypeError: wrong argument type Hash (expected Data)

Tôi đã thử một vài điều mà tôi đọc trực tuyến để sửa chữa nó, nhưng không làm việc. Tôi đã kết thúc việc viết lại đá quý để sử dụng ActiveSupport::JSON.decode thay vì JSON.parse.

Tác phẩm này không bền vững ... Tôi không thể đá quý mỗi lần tôi muốn sử dụng đá quý yêu cầu đá quý JSON.

Cập nhật: Giải pháp tốt nhất của vấn đề này là nâng cấp lên Rails 2.3 hoặc cao hơn, để khắc phục sự cố.

+1

Tại sao câu hỏi này được đánh dấu là "wiki cộng đồng"? –

+0

Tôi không biết, tôi chỉ nghĩ rằng tôi sẽ thử điều đó và xem nó làm gì. –

+0

Tôi cảm thấy đau đớn của bạn, tôi hy vọng mớ hỗn độn này sẽ được sắp xếp vào một ngày nào đó – MatthewFord

Trả lời

2

Cập nhậtSửa lỗi này chỉ áp dụng cho Rails < 2.3. Như Giles đề cập dưới đây, họ đã sửa lỗi này bằng 2,3 nội bộ sử dụng nhiều kỹ thuật tương tự. Nhưng hãy cẩn thận nỗ lực trước đó của đá quý json tại Rails khả năng tương thích (json/add/rails), , nếu được yêu cầu rõ ràng sẽ phá vỡ tất cả mọi thứ trên một lần nữa.

Ý của bạn là bản thân tuyên bố require 'json' làm tăng ngoại lệ đó? Hoặc bạn có nghĩa là khi bạn gọi @something.to_json(:something => value) bạn nhận được lỗi? Sau đó là những gì tôi mong đợi, nếu bạn có một vấn đề đòi hỏi phải có đá quý JSON thì tôi không chắc chắn những gì đang xảy ra.

Tôi vừa gặp sự cố này với đá quý oauth. Trong trường hợp của tôi, không có xung đột thực sự, vì đá quý oauth không phụ thuộc vào việc triển khai to_json. Do đó, vấn đề là JSON đang ghi đè các khai báo ActiveSupport. Tôi đã giải quyết điều này bằng cách chỉ cần yêu cầu json trước khi ActiveSupport được tải. Đặt

require 'json' 

bên trong Rails::Initializer đã thực hiện thủ thuật (mặc dù đặt sau khối không).

Điều đó cho phép ActiveSupport ẩn cài đặt JSON mặc định thay thế.

Bây giờ nếu bạn đang sử dụng một đá quý thực sự phụ thuộc vào việc thực hiện JSON to_json thì bạn đang lên một con lạch. Đây chắc chắn là điều tồi tệ nhất của lập trình meta, và tôi sẽ ủng hộ cho các nhà phát triển Rails và JSON để giải quyết xung đột, mặc dù nó sẽ gây đau đớn bởi vì người kia sẽ phải phá vỡ tính tương thích ngược.

Trong ngắn hạn, tác giả đá quý có thể thu hẹp khoảng cách bằng cách hỗ trợ cả hai triển khai. Điều này là ít nhiều khả thi tùy thuộc vào cách đá quý sử dụng phương pháp này. Trường hợp xấu nhất là một ngã ba chính thức (ví dụ: gemgem-rails).

+0

Vâng, ý tôi là khi tôi sử dụng thứ gì đó gọi là 'json' nó sẽ thổi bay phiên bản Rails của to_json khiến tôi đau nhiều. Cảm ơn các đề xuất của bạn. Bạn có may mắn với tùy chọn được đề xuất sử dụng yêu cầu 'json/add/rails' không? Tôi không thể làm điều đó. –

+0

chỉ yêu cầu hoạt động lần đầu tiên bạn gọi nó, vì vậy nếu bạn gọi nó trước khi phiên bản Rails được tải, nó sẽ không làm bất cứ điều gì khi plugin yêu cầu nó. Tôi đã xác minh điều này trong thực tế, đặt nó trong khối Rails :: Initializer. Không có ý tưởng bout điều json/add/rails, nhưng tôi không nghĩ rằng nó là cần thiết. – gtd

0

Tôi chắc rằng họ đã sửa lỗi này trong 2.3 nhưng tôi không thể nhớ cách thực hiện.

+0

Vâng, tôi nghĩ rằng họ đã thoát khỏi gọi to_json trực tiếp. Thay vào đó bạn xác định as_json hoặc bạn gọi JSON.generate hoặc ActiveSupport :: JSON.encode trực tiếp. Và với công cụ phụ trợ JSON mới, tôi nghĩ rằng ActiveSupport :: JSON.encode sẽ sử dụng thư viện ưa thích của bạn. –

0

Tôi chưa thử nó, nhưng có vẻ như Rails 2.3.3 cung cấp cho bạn một số kiểm soát:

ActiveSupport::JSON.backend = 'JSONGem' 

Found here

+0

Vâng, Rails 2.3+ khắc phục sự cố này. –

0

Trong tôi mặc dù trường hợp duy nhất, tôi đã có một Ruby (phi rails) ứng dụng thực sự tải một ứng dụng Rails (từ một tải cấu hình/environment.rb) cũng như một số đá quý tham chiếu json. Điều này khiến tôi đau đầu rất lớn do thực tế là tôi không thể thay đổi tập tin environment.rb của ứng dụng Rails. Tôi đã kết thúc forking một số đá quý để có được json để làm việc mà không nâng cao TypeError sợ hãi: sai đối số loại Hash (dự kiến ​​dữ liệu) tin nhắn.

tôi đã có một số may mắn với giải pháp này, đó là hoàn toàn ngược lại là câu trả lời wiki cộng đồng trên ... http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html mà về cơ bản ủng hộ cách gọi require 'active_support' TRƯỚC require 'json'

Đây là cách duy nhất tôi có thể làm cho nó hoạt động, và tin rằng tôi đã thử mọi thứ trong nhiều tháng.

18

CẬP NHẬT: Ngay cả với Rails 3.2, cùng một vấn đề vẫn chưa được khắc phục. Các khó chịu hack để buộc tải đá quý json và ghi đè lên nó, đó là.

Cuối cùng tôi đã kết thúc bằng mã sau, để hoàn toàn bỏ qua ActiveSupport's to_json hoàn toàn. Đặt nó trong config/initializers/patches.rb và bạn có thể làm {}.jsonize hoặc [].jsonize để tạo chuỗi JSON. Không có xung đột với bất cứ điều gì, đảm bảo.

# Undo the effect of 'active_support/core_ext/object/to_json' 
require 'json' 
[Object, Array, Hash].each do |klass| 
    klass.class_eval <<-RUBY, __FILE__, __LINE__ 
    def jsonize(options = nil) 
     ::JSON.generate self, :quirks_mode => true 
    end 
    RUBY 
end 

Đã có 8 dòng mã làm cho ứng dụng của bạn 50 lần nhanh hơn để mã hóa JSON. Có lẽ bạn muốn làm như vậy. :)


Tôi đã gặp sự cố tương tự cho đến Rails 2.3.8.

Vấn đề là ActiveSupport::JSON.backend = 'JSONGem' là giải pháp được hỗ trợ một nửa và bạn vẫn cần tự ghi đè lên một số bộ mã hóa. (CẢNH BÁO:. Cho Rails 3.x, trong đó sử dụng MultiJson, nó phải là ActiveSupport::JSON.backend = :json_gem ít nhất, hoặc nó sẽ âm thầm không-op)

Trong trường hợp của tôi, tôi cần phải ghi đè lên String#to_json vì JSON ngọc 1.4. 3 là tốt hơn ở chỗ nó không mã hóa một cách mù quáng các ký tự không phải ascii-nhưng-hợp lệ-UTF8 ở dạng "\uXXXX" nơi không cần thiết, vì vậy bạn nhận được các byte ngắn hơn (tốt cho tuần tự hóa) và các kết quả dễ đọc ("日本語") trông hấp dẫn hơn đôi mắt của tôi hơn "\u65e5\u672c\u8a9e").

Dưới đây là các bản vá khỉ mà tôi đã sử dụng - đặt đoạn mã sau vào config/initializers/patches.rb

module ActiveSupport 
    module JSON 
    module Encoding 
     class << self 
     def escape(string) 
      ::JSON.generate([string])[1..-2] 
     end 
     end 
    end 
    end 
end 

và bạn đang miễn phí để sử dụng to_json về bất cứ điều gì - String, Array và Hash.

+0

Điều này làm việc với sửa chữa Emoji trong Rails 3.1.3. Cảm ơn. – Chalkers

3

Sau khi chiến đấu này trong một thời .. Tôi tìm thấy giải pháp đơn giản nhất là:

if defined?(ActiveSupport::JSON) 
    [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass| 
    klass.class_eval do 
    def to_json(*args) 
     super(args) 
    end 
    def as_json(*args) 
     super(args) 
    end 
    end 
    end 
end 

đặt mà bất cứ nơi nào sau khi activesupport được nạp ..

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