RailsConf 2006 - Here we come!

Posted by Daniel Wanja Tue, 20 Jun 2006 10:13:00 GMT

Looking forward meeting you all in Chicago! There will be tons of great presentations, here is my selection:

Friday
10:45 Introduction to Capistrano
Mike Clark is just a great presenter
13:15 ??
Not sure yet
14:30 Monitoring Rails Applications in Production Environments
Too important to skim that one
15:45 Sneaking Rails into the (legacy) system
or Goeffrey's Rails Deployment on Shared Hosts
Saturday
09:00 Ajax on Rails
Let's see what the 'man' has to say
10:15 Lessons from Blinksale and IconBuffet
I am eagerly waiting for some information on the Blinksale API
11:30 Lucene Eye for the Ruby Guy
We are using successfully Ferret, but Lee did all the programming, so it's time I do some catching up
14:45 Testing Migrations
I hesitate between this and the two other talks, but I got bit a couple of time with migrations. So any good advice is welcome.
Sunday
9:00 Beyond DHTML: Introducing Laszlo on Rails
I am big fan of Flex and Laszlo, now that Laszlo can generate DHTML, let's see what Mike has to say.
10:15 Just the Facts (and Dimensions) -- using Rails with your OLAP data model
I had the chance of beeing part of a team that pionered the field before it was called that (back in 1987). And now I need to do some more data analysis for the soon to be releases OSX RailsLogAnalyser application (Flex+Rails). Looking forward to this talk.
11:30 Rails Takes on the Enterprise with SOA
Rails is a tuff sell to the enterprise. They invested to much into Java and .Net, so even if Rails is often a good fit, it's not even considered. So any additional ammunition to enter existing enterprises is welcome

Derailed - Denver Ruby On Rails User Group. June 15th.

Posted by Daniel Wanja Thu, 15 Jun 2006 18:51:02 GMT

19:15 Doug Fales presentation: Rails by the Waypoints: Integrating a GPS Unit and a Digital Camera in the Era of the Mashup.

Doug will present this talk at RubyConf next week, so this is kind of a dry run for him in front of 25 people at the Derailed (Denver Ruby On Rails User Group) before the big event. About 5 other people from the attendance will also attend RailsConf. Cool, Denver is in force. Doug explained how he came to Rails and integrating it with GPS data, Flicker and Google maps...that's what happens when you got the crazy idea of running long distances in the middle of no where. Check out http://walkingboss.org/ in the next month as he will release a first public version of his application. In short, you can map your walking track recorded by a gps onto a google map and also upload and link your photos to the track based on the photos time-stamps. Doug now moves onto the "What I learned" writing this application. Site note: the funny thing is that besides Ara, everyone in the attendance uses a Mac. Ok, back to the presentation. Doug sees Ruby on Rails as the glue between the data and the client-side of the application. Another challenge was writing the GPS data mangling libraries. He describes how Ruby helped writing different blocks of functionalities (Search using the Ferret gem and acts_as_ferret, the data models, tagging, ...). He then describes the cost of development, where Rails offers you lots for free. Finally, he concludes with comments on how rails allows for creativity by solving lots of mundane problems for you and allowing for to keep your momentum.

20:15 Now onto to Ara Howard's presentation: Meta Programming

Ara is usually more involved with the Boulder Ruby User Group. He is a Ruby person first, then a Rails person. He got into Ruby about six years ago, and works in all manner of application domains and is specialized in data mangling (not directly his words). He defines Meta-programming as being code that writes code. That can be at compile time or a run time. You can have reflexive meta programming where a language can be used to generate output in the same language. Ruby is a very good meta-programming language and Rails makes heavy use of meta-programming. Rather than going paraphrasing Ara, I would certainly be incorrect as he is covering lot's of ground, check out his slides (this link is to his desktop, you can also find the slides at http://codeforpeople.com). Note that just the slides won't provide enough background as the narration Ara provides and the code examples augments greatly these slides. So try to catch one of his talks if you can. The nice part of his presentation is that he is presenting advanced aspects of Ruby, the languages, that may be more obscures to people like me that dived into Ruby via Rails. Ruby provides lots of hooks for meta programming like module_eval, class_eval, instance_eval, define_method, eval (being evil).

Two excellent presentations. Thank guys! Now onto Rock Bottom for a beer.

Geoip data

Posted by Daniel Wanja Thu, 01 Jun 2006 12:20:00 GMT

As part of the Rails Log Analyzer I want to show where, geographically speaking, the different users come from. The following 'ingredients' were required to achieve this:
  • The geoip gem by Clifford Heat
  • The GeoLiteCity.dat file download from http://www.maxmind.com/app/geolitecity
  • A vectorial world map in Flash from http://www.fabiovisentin.com/world_map/vectorial_world_map.asp
  • And the Flex mx:BubbleChart component
The result is the following

20060601_geoip.gif

Note there are still some technical hurdles to overcome with the bubble chart as it behaves unexpectedly when setting the radius of the bubbles and the scaling of the world map as the background of the chart can not be precisely controlled. Also the world map needs to be zoomed in a little to make the graph more readable as not too much activity is going on at the south pole.

So now lets look at some code extracts.

Getting the geoip information [ruby]

When parsing the log we retrieve the city information related to an ip address

	require 'geoip'

	geo_ip = GeoIP.new("#{RAILS_ROOT}/data/GeoLiteCity.dat")
    	parser.items.each_with_index do |item, index|
		 geo_info = geo_ip.city(item['ip']) 
             ...
	end
The _city_ method returns the following array
         	[   hostname,			# 0 - Requested hostname
         	    ip,				# 1- Ip address as dotted quad
         	    CountryCode[code],	# 2 - ISO3166-1 code
         	    CountryCode3[code],	# 3 - ISO3166-2 code
         	    CountryName[code],	# 4 - Country name, per IS03166
         	    CountryContinent[code],# 5 - Continent code.
         	    region,			# 6 - Region name
         	    city,				# 7 - City name
         	    postal_code,		# 8 - Postal code
         	    latitude,			# 9 - Latitude
         	    longitude,			# 10 - Longitude
         	] 

Generating the geo data series [ruby] The log file data is stored in sqlite database for ease of querying and aggregation. This will also allow to wrap the application as a packaged OSX application with the database embedded in the application. The following called is invoked by the controller that simply return the result of the query to the Flex application.

  def Hit.sqlite_data(from_date, to_date)
  result = {}
    query = { :name => "geoip",
                  :sql  => "select count(*) as count, latitude, longitude, city, state, country from hits where #{scope} group by 2,3 order by 1 desc",
                 :column_names => ['count', 'latitude', 'longitude', 'city', 'state', 'county']
               }

	result[query[:name]] = Hit.geoip_serie(data, query[:name],query[:column_names], result[:hit_count][:data][0][0].to_f)
	result
   end

  def Hit.geoip_serie(serie, title, column_names, total_count)
    result = {:title => title}
    data = []
    serie.each do |item|      
      row = {'count' => (item[0].to_f / total_count)*100,
             'latitude' => item[1],
             'longitude' => item[2],
             'city' => item[3],
             'state' => item[4],
             'country' => item[5],
             }
      row['count']  = 3 #if row['count'] < 1
      #row['count']  = 5 if row['count'] > 5
      data << row
    end
    result[:data] = data
    result
  end

Rendering the series [flex]

As seen in a previous article on how to exchange data between Flex and a Rails application using JSON, the server returns the data as a string that is simply transformed to an actionscript object using JSON.decode. This object is then passed to a custom component named BubbleSerieChart (I know, I find a more descriptive name)

Passing the series to a custom Flex component
	<local:BubbleSerieChart time_serie="{geoip}" serie_name="GeoIP" />
The full source of the custom component.
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel  xmlns:mx="http://www.adobe.com/2006/mxml" 
	        title="{serie_name}" height="100%" width="100%">	

	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
		    [Bindable]
			public var time_serie:Object;
			[Bindable]
			public var serie_name:String;
			
			
			private function getLabel(item:Object, field:String, index:uint, percentValue:Number):String
        	{
            	return item.key;
        	}

		]]>
	</mx:Script>
    <mx:BubbleChart id="chart" dataProvider="{time_serie}" showDataTips="true" width="100%" height="100%" >
		<mx:backgroundElements> 
				<mx:Array> 
					<mx:Image source="@Embed('political_world_map_grey.swf')" /> 
				</mx:Array> 
		</mx:backgroundElements>


        <mx:horizontalAxis>
            <mx:LinearAxis minimum="-180" maximum="180" />
        </mx:horizontalAxis>

		<mx:verticalAxis>
			<mx:LinearAxis  minimum="-90" maximum="90"/>
		</mx:verticalAxis>
	
        <mx:series>
            <mx:Array>
                <mx:BubbleSeries xField="longitude" yField="latitude" radiusField="count"  maxRadius="5"/>
            </mx:Array>
        </mx:series>

    </mx:BubbleChart>
</mx:Panel>

Rails Log Analyzer - Rails and Flex with JSON 7

Posted by Daniel Wanja Mon, 15 May 2006 21:15:00 GMT

I started to write a small Rails Log Analyzer that provides some insight on how a given application is used. I’ve just spent three hours so far, so not too much to show, but I have found the integration of Flex with Rails for read-only purpose of the different time series pretty straight forward.

In two words…

RAILS: data.to_json

FLEX: JSON.decode(String(srv.lastResult));

On the Rails side

The controller simply transforms the Hash return by the model into a json textual representation.

the controller
class DataController < ApplicationController

  def overview
    render :text => Hit.overview_data.to_json
  end

end

This is an extract of the method that returns a Hash that contains the time series in an Array.

the model
def Hit.overview_data
    result = {}
    result[:header] = {:period => {:start => Hit.minimum(:time).to_s(:db), :end => Hit.maximum(:time).to_s(:db)}}
    result[:sessions_series] =
           {:by_day => Hit.data_serie(Hit.count(:session, :group => :day, :conditions => 'controller <> "HeartbeatController"'), "sessions by day")    }
    result
  end

On the Flex side

the view

   import com.macromedia.serialization.json.*;

   private function resultHandler(event:ResultEvent) : void
        {
            status = "Loaded. Parsing data...";
            var result:Object = JSON.decode(String(srv.lastResult));
            header = result.header;
            ts = getSerie(result.sessions_series.by_day.data);

  }

    <mx:HTTPService id="srv" url="http://10.37.129.2:3000/data/overview" result="resultHandler(event)" />

The service is invoked by the following actionscript call

        srv.send()

JSON doesn’t support Date objects out of the box, but it’s a nice way to exchange complex data such a Hash and Map between Rails and Flex.

Update: time.onrails.org. Add Notes to your time entries! 2

Posted by Daniel Wanja Mon, 08 May 2006 21:58:00 GMT

Updated time.onrails.org The new functionality is
  • Add notes to your time entries. You can now add notes from the Dashboard or your project pages.
  • Improved CSV export.
Some functionality I am considering next:
  • fixing the rendering in Internet Explorer. I just saw this bug since I installed Parallels on my MacBook pro.
  • Blinksale integration, I started to write the UI to submit a time section to generate an invoice via Blinksale, but I am still waiting to get access to the api. Unfortunatly I didn’t make to the beta of the API. I even tried to convince Josh Williams from Firewheel Design, to let me in on it, but without success. Thanks Josh for the quick response anyhow!

remote_function :with 3

Posted by Daniel Wanja Mon, 01 May 2006 16:08:00 GMT

<%= select_tag "content_type",  options_for_select(content_type_options),
 { :onchange => 
    remote_function(
         :url => {:action => 'filter_by_content'}, 
         :with => 'Form.Element.serialize(this)')  } %>

The above code allows to submit via javascript the selected value of a combo box. The remote call is triggered via the onchange event handler of the select tag. Notice the parameters to the remote function call :url, as usual, but also the :with parameter. The :with option can be very useful if you need more control on what data needs to be sent to the server. In this case we use Form.Element.serialize that url encodes all the parameters found in a given div (doesn’t need to be a form). In this case the content_type=snippet is passed to the server.

An eCommerce platform in Ruby on Rails 5

Posted by Daniel Wanja Thu, 27 Apr 2006 07:00:00 GMT

I have the chance to be part of an amazing team since last October that created a new generation of eCommerce platform using Ruby on Rails that will power hundreds of high profile ecommerce websites. The first website powered by this platform is

www.nationaltabletennis.com

Gately’s, the company behind this development had the foresight one year ago to start the development from scratch of the three major applications forming the platform…using Ruby on Rails. This decision was driven by their technical director, Solomon White, who saw the potential of Rails that not many realized at that time and decided to form a top notch team. The three applications are order management, store builder, and the storefront engine. The storefront engine can drive multiple stores. You can get an idea of what such a store looks a like at www.nationaltabletennis.com. However most of the development went into the two back-end applications, that not only look amazing, but offers possibilities that will make news in the future.

Each of the three components of the platform consist of a large application by it-self. The storefront and the store builder are new applications and the order management replaces an older php applications. Together these applications have well over one hundred model classes. This is just to give an idea of the scale of the applications.

Now, the question is how well is Ruby On Rails adapted for larger scale development with a team of 5 developers and 1 designer?

Ruby On Rails kicks ass.

The many decisions that the Rails environment takes for you allows you to concentrate on what is important, like business logic, user interaction, quality. You spend very little time in the plumming of the application asking yourself where things should go or what artifacts should be used. Rails did these descisions for you. In addition, the different ways you have to exercise immediately a code change without any delay, by the console, through unit tests, or via a page refresh provides a dynamism to the development cycle that cannot be described in words but needs to be experienced. You can perform a quantity of changes in an hour that cannot be done in other environments like java. Not only code changes, but with the database migrations you can go back and forth between different data model structures, just to experiment. You start not just coding the first thing you decided on, but you start going in a “Oh, let’s try this” mode. Not all is shiny however. We had some difficulties sharing code between the three systems that had common model, views, and controllers. This was for the access rights. For some mysterious reasons I didn’t feel using the Plugins Engine that specifically addresses this problem. So I started to role-my-own, lighter version of a plugin engine, which works but is still causing some headaches from time to time. On the other hand, using the plugin architecture to share common code that doesn’t rely on views, is a simple and great solution. Furthermore to integrate the three applications we used secured, RESTfull http requests. This approach is so much simpler than webservices and with Rails you can modify the two applications that needs interaction in parallel, refining the interaction protocol, again seeing the results of any change immediately.

There is way more to describe, but as a former Java Enterprise developer and a former Microsoft Solution Developer, I can say that Ruby On Rails just kicks ass and leaves these other environments in the shadow.

If you are starting a new enterprise or web development project, you got to consider Ruby on Rails!

Update: time.onrails.org. Capistrano Rocks!

Posted by Daniel Wanja Wed, 19 Apr 2006 21:50:00 GMT

Updated time.onrails.org The new functionality is
  • A first version of data export to text, csv, and xml. See the export icons in the bottom right of the projects and dashboard page.
  • A mini system message board. So we can leave you a message, i.e. for planned system maintenance downtime, or to announce new functionality.
  • The latest version of the Gruff Graphs

I realized that data export needs some more work as in Safari the xml doesn’t appear unless you do a view source and the csv doesn’t load Microsoft Excel directly nor adds a default .csv extension to the generated data.

We will deploy new functionality or fixes issues once a week if possible. Note that we are going to keep this application simple, but any suggestion is welcome. Contact us at time@onrails.org.

I deployed the application using Capistrano. It is pretty stressless and consists of the following steps:
rake remote:disable_web
rake remote:deploy_with_migrations
rake remote:enable_web

In this case we had a database migration, the new ‘messages’ table.

The only issue that persists is that the application doesn’t start right away after the deployment and seems to hang for about 10 minutes before comming back to life. The application is hosted on Dreamhost and we don’t have full control on how the displatch.fcgi processes are launched.

It’s now up and running, so enjoy!

render :update to |page| 2

Posted by Daniel Wanja Tue, 18 Apr 2006 11:54:00 GMT

In the following test I was checkeing out of the javascript that is generated using the render :update call. Note that using a functional test is also a nice way to explore some of the prototype_helper functionality.

page.call 'mycall', 'a', 2, 3      # -->  mycall("a", 2, 3);'
page.my_class.my_method 'a', 12    # -->  MyClass.myMethod("a", 12);
Now one issue I had was figuring out how to pass a javascript variable to a javascript call. I.e. mycall(p1, p2). The only way I found it so to use the page << method. After a little hacking I managed to pass javascript variables to a method using the page.call. See the use of the JsArugmentList class here after. Note it does get’s a little cluttered and the page << remains easier to read. Please let me know if you find a more elegant way to achieve this.
rjs_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
require File.dirname(__FILE__) + '/../test_helper'

# Little hack to allow passing javascript variables as argument to page.call
class JsArgumentList
  def initialize(*arguments)
    @arguments = arguments
  end
  def to_json
    @arguments.join ', '
  end
end

class RjsController < ActionController::Base
  def rescue_action(e) raise e end;
  # See prototype_helper.rb for implementation of the 'page' methods.
  def page_call
    render :update do |page|
      page.call 'mycall', 'a', 2, 3
      page.assign 'p1', 'str1'
      page << 'mycall(p1, p2);' 
      page.call 'mycall', JsArgumentList.new(:p1,:p2)  #equivalent to previous line
      page.my_class.my_method 'a', 12 
    end
  end
end

class RjsControllerTest < Test::Unit::TestCase
  def setup
    @controller = RjsController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end
  def test_page_call
    get :page_call
    javascript = @response.body.split("\n")
    assert_equal 'mycall("a", 2, 3);',          javascript[0]
    assert_equal 'p1 = "str1";',                javascript[1]
    assert_equal 'mycall(p1, p2);',            javascript[2]
    assert_equal 'mycall(p1, p2);',            javascript[3]
    assert_equal 'MyClass.myMethod("a", 12);',  javascript[4]
  end
end

Graphs with Gruff (followup)

Posted by Daniel Wanja Fri, 14 Apr 2006 06:49:00 GMT

The solution from the source ;-) I checked it out and it now works as advertised, just add g.minimum_value = 0 to the Gruff::Bar before rendering it (g.to_blob).

Note that axis starting at zero.

Without the minimum_value With the minimum_value set to zero

Older posts: 1 ... 15 16 17 18 19