mshiltonj
mshiltonj

Reputation: 316

Decode JSON in rails simple string raises error

I'm trying to roundtrip encode/decode plain strings in json, but I'm getting an error.

In rails 2.3. w/ ruby 1.8.6, it used to work.

>> puts ActiveSupport::JSON.decode("abc".to_json)
abc
=> nil

In rails 3.1beta1 w/ ruby 1.9.2, it raises an error.

ruby-1.9.2-p180 :001 > puts ActiveSupport::JSON.decode("abc".to_json)
MultiJson::DecodeError: 706: unexpected token at '"abc"'
    from /home/stevenh/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:147:in `parse'
    from /home/stevenh/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:147:in `parse'
    from /home/stevenh/.rvm/gems/ruby-1.9.2-p180/gems/multi_json-1.0.1/lib/multi_json/engines/json_gem.rb:13:in `decode'
    [...]

This is pretty much the same question discussed at nil.to_json cannot be parsed back to nil?

But nil used to work in 2.3/1.8.7 as well.

puts ActiveSupport::JSON.decode(nil.to_json)
nil

Is this the new normal?

Upvotes: 12

Views: 7803

Answers (3)

Fabio
Fabio

Reputation: 19176

If you need to restore that behavior follow these steps, i.e.

# in your Gemfile
gem 'yajl-ruby'

# in your application.rb
require 'yajl/json_gem'

After those steps:

Loading development environment (Rails 3.2.8)
[1] pry(main)> puts ActiveSupport::JSON.decode("abc".to_json)
abc
=> nil
[2] pry(main)> puts ActiveSupport::JSON.decode(nil.to_json)

=> nil

Upvotes: 0

Joe Goggins
Joe Goggins

Reputation: 1338

Yes, what is happening in Rails3 is the new normal. The changes you illustrate seem like a reflection of a maturing framework.

Methods named "encode" & "decode" should be expected to be perfectly compliant with the JSON spec, and inverses of one another.

String#to_json, on the other hand is a behavior-ish type of method that functions as a convenience for building more complex JSON objects presumably used internally (within ActiveSupport) when Array#to_json or Hash#to_json encounter a String value as one of their consituent elements.

Upvotes: 1

Yardboy
Yardboy

Reputation: 2805

This change occurred with the switch from ActiveSupport's JSON backend to MultiJson that was included in Rails 3.1.0.rc1. Per the MultiJson project team, the current behavior is correct and the previous implementation was faulty due to RFC4627's specification of the JSON grammar:

2.  JSON Grammar

   A JSON text is a sequence of tokens.  The set of tokens includes six
   structural characters, strings, numbers, and three literal names.

   A JSON text is a serialized object or array.

      JSON-text = object / array

As neither "abc" nor "/"abc/"" are serialized objects or arrays, an error when attempting to decode them is appropriate.

The diagrams from the JSON website reinforce this specification.

That being said, this would seem to imply a bug in the to_json implementation that results in:

ruby-1.9.2-p180 :001 > "abc".to_json
 => "\"abc\""

Upvotes: 8

Related Questions