This project is archived and is in readonly mode.

#4925 ✓ duplicate
Nate Wiger

Rails 3 to_json incompatible with JSON core library

Reported by Nate Wiger | June 21st, 2010 @ 07:53 PM

It appears that Rails 3 changes the signature of to_json vs the JSON core lib. Unfortunately, this breaks ActiveRecord and other components when trying to use them outside of Rails. I've hit this with Sinatra, Sequel, and a couple other toolsets that rely on the core JSON library.

Here's one example backtrace from Sinatra:

ArgumentError: wrong number of arguments (2 for 1)
/Users/nwiger/Workspace/server/app/routes/message_routes.rb:6:in `to_json'
/Users/nwiger/Workspace/server/app/routes/message_routes.rb:6:in `block in <class:Main>'
/Users/nwiger/.rvm/gems/ruby-1.9.2-head/gems/sinatra-1.0/lib/sinatra/base.rb:865:in `call'
/Users/nwiger/.rvm/gems/ruby-1.9.2-head/gems/sinatra-1.0/lib/sinatra/base.rb:865:in `block in route'

The code that generated that was (AR3):

class Message < ActiveRecord::Base
  scope :unread, where(:is_read => false)

  def self.find_and_read_for(user_id)
    m = where(:user_id => user_id).unread.all
    update_all({:is_read => true}, ['id IN (?)', m]) unless m.empty?
    m
  end
end

Then in Sinatra:

# Return unread messages and mark read
get '/messages/read.json' do
  @messages = Message.find_and_read_for(current_user_id)
  @messages.to_json
end

The problem is that the JSON gem supports a *splat as its arg signature, whereas Rails 3 does not:

http://github.com/rails/rails/blob/master/activesupport/lib/active_...

It seems a simple patch to change that signature to this:

def to_json(*options)
  ActiveSupport::JSON.encode(self, options)
end

Would solve the issue.

I'm not sure why AR2 is not affected in the same way, since it appears to override to_json similarly, but I have seen this with a couple test apps now, and only with AR3.

Thanks,
Nate

Comments and changes to this ticket

  • Fluxx

    Fluxx June 26th, 2010 @ 12:00 AM

    We're running in to this inside of Rails3 beta4 as well:

    Loading development environment (Rails 3.0.0.beta4)
    irb(main):001:0> Rails.version
    => "3.0.0.beta4"
    irb(main):002:0> {1=>2}.to_json
    => "{\"1\":2}"
    irb(main):003:0> {1=>:a}.to_json
    ArgumentError: wrong number of arguments (2 for 1)
        from (irb):3:in `to_json'
        from (irb):3
    irb(main):004:0> {1=>{2=>:a}}.to_json
    ArgumentError: wrong number of arguments (2 for 1)
        from (irb):4:in `to_json'
        from (irb):4
    irb(main):006:0> {1=>{2=>1}}.to_json
    => "{\"1\":{\"2\":1}}"
    @@@@
    
    In particular, it seems to only happen when the value of a hash is a symbol.
    
  • Rasmus Rønn Nielsen
  • iuri matias

    iuri matias June 28th, 2010 @ 11:17 AM

    We are running into the same problem

  • Jeremy Kemper

    Jeremy Kemper June 28th, 2010 @ 05:27 PM

    • State changed from “new” to “duplicate”
    • Importance changed from “” to “Low”

    JSON gem overloads to_json with its own private encoding API so we'll continue to run into these issues until that lib changes its approach.

  • Nate Wiger

    Nate Wiger July 8th, 2010 @ 11:18 PM

    For others wondering, the only way I've found to workaround this is to put this in environment.rb, after the initializer block

    class Array
      def to_json(*a)
        ActiveSupport::JSON.encode(self)
      end
    end
    

    This also works for Sinatra/etc if you put it in the main application.rb file (or whatever yours is called).

    -Nate

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Tickets have moved to Github

The new ticket tracker is available at https://github.com/rails/rails/issues

Shared Ticket Bins

Pages