-3

In ruby:

class Obj
  attr_accessor :price
end

my_ruby_obj = Obj.new

puts my_ruby_obj.to_json

"\"#<Obj:0x1c9b018>\""

Server sends my_ruby_obj.to_json to browser (sinatra, with content_type :json) in response to a jquery ajax request (with $.get), which correctly defines a return type of json, and launches a callback function(data) which does:

console.log(data);

which returns:

#<Obj:0x1c9b018>

Now how do I access "data.price" attribute in javascript/jquery as I would normally do on a ruby object to access its attribute? ("my_ruby_obj.price")

I tried with console.log(data.price);

> Undefined

I feel I am missing a big piece here.. and I guess it has to do with how json works with objects..

Any help ? If possible, I'm looking for a correct way to do it with jquery.

Thanks

edit: trying to understand what is going on, I tried this in the callback:

newdata = $.parseJSON(data);

but debug console halts on it showing:

> uncaught exception: Invalid JSON: #<Obj:0x1c9b018>

I did call .to_json on the ruby object, so why it says so? ...

[[new_edit:]]

Seems like ruby json serialization for objects from custom classes is not working as I supposed:

Quoting from here: https://stackoverflow.com/a/4464721/988591

It will be a bit more difficult for objects from your own classes. For the following class, to_json will produce something like "\"#<A:0xb76e5728>\"". This probably isn't desirable. To effectively serialise your object as JSON, you should create your own to_json method.

and examples are following... But.. wow... isn't there an easier way ?

Community
  • 1
  • 1
Redoman
  • 3,059
  • 3
  • 34
  • 62

2 Answers2

0

You're returning the string representation of your object via javascript, not the object its self.

You need to return a JSON representation fo it:

render json: my_ruby_obj.to_json

Or even better, if you know the fields you need to access:

render json: {price: my_ruby_obj.price}
Michael Shimmins
  • 19,961
  • 7
  • 57
  • 90
  • are you sure this applies to Sinatra and not to Rails? Please look at the following example http://nathanhoad.net/how-to-return-json-from-sinatra – Redoman Nov 05 '12 at 00:34
  • 1
    The same theory will apply in regards to what you're sending over the wire from the server to the client via JSON. Not sure if `to_json` is available in a sinatra app. You're just sending a simple string "#" - need to send actual json. – Michael Shimmins Nov 05 '12 at 00:40
  • you were right, but it leads to an "ugly" solution. :\ check new_edit to the question please. – Redoman Nov 05 '12 at 01:48
0

Ok I found exactly what I was looking for! An automated quick solution, which also comes with other side benefits (more speed!).

The standard json gem only works for some classes (Array, Hash,..) and can't translate a custom class/object you have created to JSON. It doesn't know how to organize data, unless you write yourself a custom .to_json method for your class, which is what I was tring to avoid..

So in the end I found a gem called Oj: Optimized Json (gem install oj)

Quoting the authors:

Optimized JSON (Oj), as the name implies was written to provide speed optimized JSON handling. It was designed as a faster alternative to Yajl and other the common Ruby JSON parsers. So far is has achieved that at about 2 time faster than Yajl for parsing and 3 or more times faster writing JSON.

Oj has several dump or serialization modes which control how Objects are converted to JSON. These modes are set with the :mode option in either the default options or as one of the options to the dump() method.

:object mode will dump any Object as a JSON Object with keys that match the Ruby Object's variable names without the '@' character. This is the highest performance mode.

I used it like so:

json = Oj.dump(guy, mode: :object) but in my case it worked without mode: :object as well.

now console.log(data); shows:

({'^o':"Human", x:38, y:58, name:"Jack", bday:{'^t':1352083824.5625}, age:50})

Now that the serialization is working good, I can finally do:

console.log(data.age); // ---> 50

Serialization is faster too.

..It has been a long ride though ;)

A big Thank You goes to the library author: http://twitter.com/#!/peterohler

Community
  • 1
  • 1
Redoman
  • 3,059
  • 3
  • 34
  • 62
  • By the way, now I asking myself if a more "standard" way to deal with this is splitting the object in small bits and then serialize them, and send them piece by piece ? Like @Michael Shimmins said: my_ruby_obj.price.to_json , then my_ruby_obj.color.to_json, then..., and soo on ? Ok.. enough.. :) – Redoman Nov 05 '12 at 04:04