Associations and to_json on collections of objects

ActiveRecord’s Serialization module does provide to_json method. It allows include associations when dumping to JSON, but it works only for single objects. If You want to run it against collection, returned by find :all You will get:

>> Model.all.to_json :include =>:association
TypeError: wrong argument type Hash (expected Data)
	from (irb):13:in `to_json'
	from (irb):13

If You want to get in JSON collection with some associations You have to do it manually:

    @companies = Company.all, :include => :address
    render :text => "[ %s ]" % @companies.collect{ |c|
      c.to_json(:include => :address)
    }.join(","),
      :content_type => 'application/json'

GMarkerManager and setImage – why it fails?

I wrote simple howto about changing icons in markers when markers is already placed on map. And I was asked question about setImage and GMarkerManger.

Problem is that when changing image with setImage old image will be displayed when user zooms map in or out – when GMarkerManager is used to place markers on map.

GMarkerManager was introduced in November 2006, and it has goal to help manage huge amounts of markers on map. For markers added to map via manager You can define on which zoom levels markers should be visible. This allow to keep map not so crowded, when displaying larger area.

GMarkerManager tracks zoom level and display only needed markers and tries to keep memory usage as low as possible. This mean that not all data about markers is keep in memory. For example – if marker is not visible on current zoom level or in viewport image representing it is discarded. To display markers properly GMarkerManager creates new images from GIcon class, when changing zoom.

This is why setImage fails in this case – image is changed, but when user changes zoom all markers images gets recreated from GIcon. So what can be done? We can change image in icon definition:

marker.setImage("htp://example.com/new_image.png")
marker.getIcon().image = "htp://example.com/new_image.png"

However can backfire if we use common GIcon object to initialize more than one marker (and this is usually the case). When we change image in GIcon, after next refresh all markers created from this GIcon instance will get new image. Like in this example. Place two icons on map (just click) and click Change image. After zoom out You will see that both markers has new icon…

So what we can do about it?

First we can create separate GIcon for each marker – but this will have impact on memory usage. If this is not suitable, so You have to write some own replacement for GMarkerManager. But there is good news – You don’t have to start from a scratch. Google has opensourced GMarkerManager and full code (not obfuscated) is available in GMaps Utility Library (library announcement, GMarkerManager code is available under this link).

I guess there is already some solution written to solve this problem, but I’m not aware of any – does anybody found/wrote something useful?

TLabel – simple, smaller labels on Google Maps

If You use Google Maps API, probably You want to use smaller windows/labels on map than default infoWindow, which happens to be huge and bloated.

When I started Run-N-Share almost two years ago, I stumbled upon TLabel, minimalistic library for creating labels on Google Maps. It is abandoned project, but it still works with current API version (110a). However there are some issues with it. For example when You close label, and then move map or zoom in or out, there will be Java Script error. I have fixed recently this error for RNS, so if You are still using TLabel, here are some details.

When removeTLabel is called, DOM element representing label is destroyed, but handlers registered to refresh view after zoomend or moveend events does not get unregister. To fix it change lines with GEvent.bind in TLabel.prototype.initialize to:

    this.zoom_handler = GEvent.bind(a,"zoomend",this,function(){this.setPosition()});
    this.move_handler = GEvent.bind(a,"moveend",this,function(){this.setPosition()});

Then in GMap2.prototype.removeTLabel add at function begin:

    GEvent.removeListener (a.zoom_handler)
    GEvent.removeListener (a.move_handler)


Eventually – does anybody knows similar library to TLabel? Maybe it is time to switch?