This project is archived and is in readonly mode.
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 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 June 28th, 2010 @ 10:26 AM
I think this is a duplicate of:
https://rails.lighthouseapp.com/projects/8994/tickets/4494-ruby-192... -
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 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 »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>