Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Rails 3 to_json incompatible with JSON core library

#4925

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

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

State: duplicate
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Fluxx
    Fluxx

    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.
    

    June 26th, 2010 @ 12:00 AM

  2. Rasmus Rønn Nielsen
  3. iuri matias
    iuri matias

    We are running into the same problem

    June 28th, 2010 @ 11:17 AM

  4. Jeremy Kemper
    Jeremy Kemper
    • 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.

    June 28th, 2010 @ 05:27 PM

  5. Nate Wiger
    Nate Wiger

    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

    July 8th, 2010 @ 11:18 PM