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:
1
2
3
4
5
| 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:
1
2
3
4
| 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.