Blog moved
Suite75 now is Floorplanner. Our blog is moved to http://techblog.floorplanner.com. Please update your bookmarks and RSS readers!
Twitterin’ again
I created my first Twitter account about half a year ago. I updated it every 5 minutes and in between I kept hitting the refresh button to see if there was any news from me friends. I liked the concept of Twitter but it just took too much of my time, so I decided to stop and delete my account.
After reading We Travel in Tribes I got interested again. As a social network I like Twitter because it keeps me up to date on what my friends are doing. But it’s more, like Rands points out:
I want to know more people, and sure, it’s interesting to see what they’re up to, but what I really want to know is what is going on inside their heads with a minimum of fuss. I want to see how they see the world. This is why I follow people on Twitter.
With this in mind I created a new Twitter account and added some friends to my list. I hope I can control my twitter time better then last time
This is me: http://www.twitter.com/hertog
JSON parser for ActionScript2
It took us some time, but now we see the virtues of JSON. We’re moving from XML to JSON to communicate with the outside world. The Floorplanner 2D app is (still) AS2 and I’m very happy to see that 5etdemi created a nice JSON parser in AS2.
Saves me a lot of work, thanks!
BitmapData.draw(..) cross domains
Since recently we create a thumbnail image of every Floorplanner plan that is saved. To create a 240×180px image we use the BitmapData class (AS2) to get the pixel info and we send it to our server to create the PNG/JPG.
It can happen that the content (images, swf’s) has to be loaded from a different server then the server that holds the HTML page with the Flash app. We noticed that the Flash Security Sandbox doesn’t like that (surprise!) by not allowing us to use the BitmapData.draw(..) method.
Abdul found a solution for AS3 and we ported it to AS2. We only needed a way to load the crossdomain.xml file from the domain of the HTML page. This sniplet uses Javascript to determine the domain and loads the policy file (crossdomain.xml) from it.
var url:String = String( ExternalInterface.call(
"function(){ return document.location.href.toString();}"
));
var split:Array = lCurrentUrl.split( "/" );
System.security.loadPolicyFile( "http://"+ split[2] +"/crossdomain.xml" );
Developing RESTful APIs in Rails
As you may have read on this blog, we are working on a RESTful API for Floorplanner. This post contains some random observations I have made and questions I had (and still have) during the development.
to_xml incompatible with to_json
ActiveRecord#to_json does not seem to be fully compatible with ActiveRecord#to_xml. With to_xml, it is possible to overwrite the to_xml method of your models. The overwritten method will be called, even if an instance of such a model is :included within the XML of another model. For to_json however, only the overwritten method of the instance you call to_json on will be executed; for every included model, the default implementation is used.
A workaround in most cases is to pass every option to the initial call of to_json:
@object.to_json(:except => [:id],
:include => {:related_objects => {:except => [:id, :object_id]}})
Weird behavior in to_xml called on an array of objects
One model in our project seems to have some caching issues in production mode. If to_xml is called on a collection of instances of this model, the results seems to get stored in cache. On every call, the result is appended to this cached value. The result is a lot of repetition of the same XML, which is invalid XML. The weird part is that it works OK if it is only a single instance of this model or if config_cache_classes == false (a development environment). to_json does not seem to have this problem either. All other models are unaffected as well. A more complete write-up of the problem can be found here.
I am still not able to figure out what causes this behavior and I am currently working around this issue by using some String#split-magic on the result of the to_xml-call. I know this is extremely ugly, so if anybody has experienced a similar problem, please let me know! It’s driving me nuts!
Testing an XML API
What is the best way to test a REST API, besides the Unit-tests that are already in place? Currently, I have an integration test suite, with a lot of testing code that looks like this:
def test_create_project
post projects_path(:format => :xml),
{:project => {:description => 'Original description'}}
assert_response :created
@new_project_location = headers['location'].first # array?
get @new_project_location
assert_response :success
project_doc = REXML::Document.new(response.body)
assert_equal 'Original description',
project_doc.elements['//description'].text
end
It works, but is isn’t very elegant in my eyes. Moreover, all that XML parsing is making the test suite slower and slower. Does anybody have suggestions to build a cleaner and faster test suite for a RESTful XML API? By the way, is there an easy way to POST an XML document rather than “normal” POST-parameters in these calls?
Using mousewheel in the Flash Player on Mac OS X
The Flash Player on OS X currently lacks support for mousewheel events. This means that users cannot use their mousewheel on OS X, in the Floorplanner we use the mousewheel to easily zoom in to your Floorplan. After reading this post from pixelbreaker, I was inspired to implement this in the Floorplanner which was, in fact, very easy. I decided to only use the JavaScript class of pixelbreaker, which sends the mousewheel events to the Flash Player (on the Mac). In the Floorplanner ActionScript this event is handled by our own internal Event management system, which sends the Event to the reponsible part of the code. So thumbs up for pixelbreaker, for making this really easy to implement!
RAPIDoc Rails Rest Api documentation generation, well just RAPIDoc…
Today I setup the first version of a RAPIDoc, a Rest API Rails Documentation Generator and we decided to open source this thing, from now on let’s call it RAPIDoc. It is a API code generator for Rails, describing your Rest resources. We we’re looking for a way to fully integrate documentation of our API into the code base, like Rdoc does. Rdoc didn’t suit our needs, cause it has got nothing to do with Rest and resource stuff, so we decided to hack something together and gave it a name: RAPIDoc.
What does it do?
It generates a API controller containing documenation maked up in a special language. It parses controllers you specify, and generates a ApiController with appropriate views for it. This makes it very easy to document a Rest API. For methods you use, and according to ERB templates you specify it generates the views for you. It doesn’t parse your routes.rb, it was not needed for us, but may be a nice extension for it.
Well how is that RAPI doc looking? Put this in front of a Restful method.
=begin rapidoc
url:: /projects
method:: GET
access:: FREE
return:: [JSON|XML] - some project
param:: page:int - the page
param:: per_page:int - max items per page
Get a list of projects. This method uses pagination. If you want to retreive project 1-10 for example:
/projects?page=1&per_page=10.
=end
For each resource you specify, a view is created and it is put into the index.
Opensource
It is available from now on on:
http://code.google.com/p/rapidoc/
If you find it useful and you want to change some things, become a submitter. Ow yeah, just a note: really experimental code
JSON Validator
I’m currently working on a JSON export from the Floorplanner and I’m glad I found the excelent JSON Validator made by arc90 lab. They made the debugging process a lot easier. Thanks guys!
Finding the correct IP address in Rails
Today, I have added a server switch to Floorplanner.com. Now, it will load the floorplanner elements from the server that is nearest to you, which can yield a significant improvement in the initial loading time of your floorplans.
To determine your location, your IP address is matched against a table of locations. This worked fine in our development version, but it didn’t work at all on the production server. After some searching, I found that our server configuration was causing this. We use Apache as our web server, which uses mod_proxy to send the request to our Mongrel cluster. This intermediary step caused the IP address that Rails would receive to always be the IP address of the Apache server: 127.0.0.1. Therefore, the location matching did not work.
However, I found that mod_proxy adds an additional header to the request with the original IP address: HTTP_X_FORWARDED_FOR. This header can be used for our purpose. Now, I use the following function to determine the correct IP address:
def determine_ip(request) # use HTTP_X_FORWARDED_FOR if available # otherwise fall back to default header request.env["HTTP_X_FORWARDED_FOR"] || request.remote_addr end
On a related note: to match an IP address against ranges of IP addresses in our location table, it must be converted from a string (”1.2.3.4″) to a number (16909060). I use the following oneliner, which uses some nice functional programming tricks and an application of bit-shifting:
def numeric_ip(ip_str)
ip_str.split('.').inject(0) { |ip_num, part|
( ip_num << 8 ) + part.to_i }
end
Yes, I am really proud if this function!
UPDATE: I just found out that request.remote_ip does the same as my determine_ip-function. Unfortunately, it only works in Rails 2.0.
Consume SOAP web service from Javascript
I wanted to get some data from a web service using Javascript. I looked at several Javascript classes (like this), but because the web service was running on another server it got a little troublesome. As a solution I tried to call the web service through a proxy, but that didn’t make it any easier.
Jaap suggested to take a look at NuSOAP, a -kinda old- SOAP toolkit for PHP. With an AJAX request I could call a PHP page that uses NuSOAP to consume the web service. It was actually easier then I thought it would be.
To make the AJAX call from Javascript I used Prototype and this script:
function doRequest() {
var url = "ajax/consume_webservice.php";
var param1 = "value1";
var param2 = "value2";
var params = "param1="+ param1 +"¶m2="+ param2;
new Ajax.Request ( url, { method: 'POST', parameters: params,
onComplete: onResult } );
}
function onResult( result ) {
alert( result.responseText );
}
The PHP file consume.php looks something like this:
< ?php
$param1 = isset( $POST_['param1'] ) ? $POST_['param1'] : false;
$param2 = isset( $POST_['param2'] ) ? $POST_['param2'] : false;
// this is the only file I used from the NuSOAP project
require_once( "nusoap.php" );
$url = webserviceurl;
$params = array( "param1" => $param1, “param2″ => $param2 );
$soap = new nusoap_client( $url, true, false, false, false, false, 0, 60 );
$proxy = $soap->getProxy();
$proxy->functionname( $params );
echo $proxy->response;
?>
That’s all. Do a AJAX request from Javascript to a PHP page. Then the PHP page uses NuSOAP to consume the web service and returns the result. Back in Javascript you can do whatever you want with the given data.
