to_json and Rails 2

Rails 2 changed the way to_json works on ActiveRecord objects. Prior to Rails 2, to_json returned a hash of hashes — the first level hash had the key ‘attributes’, which in turn had another hash with your field name/values.

With Rails 2, calling to_json on an AR object just gives you a hash of field name/values. The new way is easier and more intuitive. However, in breaks our code in places where we use to_json to pass AR data into JavaScript.

The changes are straightforward. There were two ways we dealt with the intermediate “attributes” hash prior to Rails 2:

  1. we used map/collect before calling to_json, i.e.: cities.collect{|c|c.attributes}.to_json
  2. we dealt with ‘attributes’ in JavaScript, i.e., var marker=markers[i].attributes

Fixing it just means removing references to the ‘attributes’ and using the ActiveRecord instance directly.

Here are all the places changes need to be made:

  • 3.8: var marker=markers[i].attributes to var marker=markers[i]
  • 4.6: all instances of result.attributes to just result
  • 4.15: var stores=<%=(@stores.collect {|s|s.attributes}).to_json%>; to var stores=<%=@stores.to_json%>;
  • 5-12: remove the to_json method from class Tower
  • 7-2: render :text=>cities.collect{|c|c.attributes}.to_json to render :text=>cities.to_json
  • 7-5: render :text=>cities.collect{|c|c.attributes}.to_json to render :text=>cities.to_json
  • 7.15: var points=<%=@towers.collect{|c|c.attributes}.to_json %>; to var points=<%=@towers.to_json %>;

13 Responses to “to_json and Rails 2”  

  1. 1 Pavel

    I use json and have no problem! This is very good think =)

  2. 2 ashchan

    In Rails 2.1, to_json seems to return hash of hashes by default.

    # Include Active Record class name as root for JSON serialized output.
    # ActiveRecord::Base.include_root_in_json = true

  3. 3 joinlee

    3.8: var marker=markers[i].attributes to var marker=markers[i].marker

  4. 4 jeremy

    I am trying to test your code in example 4-15 with rails 2.0.

    I am seeing a syntax error when using json.

    In your updated example: you said to change the code to var stores=; to var stores=;. This is the same thing. :) I also used the new update on this site and it is different.

    var points=;

    This is also throwing an error.

  5. 5 robert_d

    To see what Rails to_json function returns put this statement
    in javascript file
    alert(’request.responseText :’ + request.responseText);

  6. 6 robert_d

    @jeremy
    Put
    var stores = ;
    in map.html.erb (as it is explained above). Next see Page Source in a web browser to see what is the value of stores.

  7. 7 chris

    You should link this from the errata– I only found this page after spending a bunch of time trying to figure out why listMarkers() in chapter 3 didn’t work and eventually figuring it out myself. I even came and looked at the errata page but it’s not there. I only got here after googling “rails to_json” once I realized there was a difference in the structure in the book vs. what I was getting back.

    The upside: I learned more how to debug javascript and its interactions with rails.
    the downside: it took more time than I would have liked because I don’t know much javascript and the way it deals with objects.

  8. 8 Toby Seaman

    joinlee, thanks for your August 16th post. I was completely stumped and unable to persuade my map to retrieve the points from the DB. I had pinned it down to a to_json type problem, but got lost working out how to debug. In the end it was a case of replacing .attributes with .marker. thank you so much for that gem!

  9. 9 Max Smart

    I am using rails 2.2.2 and am only on chapter 3. I had to make this change to application.js

    var marker=markers[i].attributes to var marker=markers[i].marker

    and then it would pull the Markers already in the DB. Thanks, I am thrilled with this book.

    PS I do have a question. If I only wanted to allow ONE geocach site what would you recommend. This is what I did, but do not think it is a good idea.
    (the goal is to allow a user to select where they are from, but I only
    want to capture and store a single geocode - no addresses can be stored in the system)

    added to bottom of appl.js

    function oneTime() {
    removeListener(clicker)

    }

    window.onload = init;
    window.onclick = oneTime;
    window.onunload = GUnload;

    in init() I changed the GEvent.addListener….

    to

    clicker = GEvent.addlistener…

  10. 10 Jeff

    I must admit that I’m a little confused, too, with regards to the example for 4-15. I’ve changed it from:

    var stores=;
    to
    var stores=;

    But it keeps giving me an “invalid argument” error. Any ideas?

  11. 11 Jeff

    Actually, never mind. I figured it out. Apparentally, the error I was getting was due to the loop that placed the markers on the map. I had to change the loop to look like:

    for (i = 0; i < stores.length; i++) {
    var store=stores[i].store;
    addMarker(store.lat, store.lng, store.name);

    }

  12. 12 Michael

    anybody who is trying to get the examples running on rails 3 beta:

    rails 3 escapes erb by default. so make sure to use the raw method like this:

    var spots = ;

  13. 13 Michael

    “var spots = ;”

    is what I meant…


Buy Our Books!

(Here's Why) PHP book Rails book DOM book mashups book