Google Charts with Rails
Nothing beats some nice charts to dazzle your clients. I guess this is another addition to a couple of previous posts that go over various charting tools that can be found here and here.
If you haven’t checked out Google Charts go here to check out the API. To use Google’s charts you have to encode the data with one of the three allowable formats.
- Simple encoding uses the alphanumeric characters (A to Z, a to z, and 0 to 9) where A represents 0, B represents 1, and so on up to 9, representing 61 to provide a resolution of 62 different values. Allowing five pixels per data point, this is sufficient for line and bar charts up to about 300 pixels. Simple encoding is suitable for all other types of chart regardless of size. This type of encoding results in the shortest URL.
- Text encoding uses floating point numbers between 0.0 and 100.0 to provide a resolution of 1,000 different values. Allowing five pixels per data point, integers (1.0, 2.0, and so on) are sufficient for line and bar charts up to about 500 pixels. Include a single decimal place (35.7 for example) if you require higher resolution. Text encoding is suitable for all other types of chart regardless of size.
- Extended encoding uses pairs of alphanumeric (plus a few others that are discussed later) where AA represents 0, AB represents 1, and so on up to two periods (..) representing 4095 to provide a resolution of 4,096 different values. This is best suited for large charts with a large data range is required.
The good thing is, is that there are a few tools that are available for Rails that will do the work for us. I fooled around with the top two of them, although I am a little unsure of the status of either.
I had some issues with Google Charts on Rails as the labels would not render as they were supposed to. After looking at the source code it seemed that, by all the #TODO… comments that the development on this plugin may be discontinued.
With the first not working as I thought it would I moved onto the second. Google Charts worked very nicely and within a couple of minutes of reformatting the reporting data I had some pretty cool charts.
Since Google Charts works I never even bothered to test gchartb although I will put it on my to-do list.
So let’s create some graphs. First thing that we have to do is install the GoogleCharts gem
sudo gem install googlecharts
Once that is done we will have to add the following to the top of our controllers/application.rb file. You could also just add this line to the controller(s) that contain reporting methods.
require "gchart" #the line to add class ApplicationController < ActionController::Base ...
For the tests I created a Seller and Sale models with the following migration files.
# 001_create_sellers.rb class CreateSellers < ActiveRecord::Migration def self.up create_table :sellers do |t| t.string :name t.timestamps end end def self.down drop_table :sellers end end # 002_create_sales.rb class CreateSales < ActiveRecord::Migration def self.up create_table :sales do |t| t.decimal :amount, :precision => 10, :scale => 2 t.date :sold_on t.integer :seller_id t.timestamps end end def self.down drop_table :sales end end
And of course to test out the charts we will need some test data.
# 003_test_data.rb class SampleData < ActiveRecord::Migration def self.up # create some sellers john = Seller.create(:name => "John") susan = Seller.create(:name => "Susan") # add sales to sellers [john, susan].each do |seller| (0..20).each do |i| Sale.create(:amount => rand(1000), :seller_id => seller.id, :sold_on => DateTime.now + i.days) end end end def self.down end end
Now we have to be able to access the data in a format that will work well with charts. To do this I created a sales_report method within the Seller model.
class Seller < ActiveRecord::Base def sales_report data = [] labels = [] Sale.find_all_by_seller_id(self.id).each do |s| labels << s.sold_on.to_date.strftime("%B %d") data << s.amount end {:labels => labels, :data => data} end end
That is it for the dirty work, it is smooth sailing from here (said with a lot of sarcasm).
All we have to do now is access the data from the controller.
class SalesReportController < ApplicationController def show @report = Seller.find(params[:id]).sales_report end end
and make sure that the routing is set up by adding the following to the router.rb file
map.resources :sales_report
To display it on the page I created a show.html.erb file with the following code.
<%= image_tag Gchart.bar(:title => 'Sales', :size => '600x200', :data => @report[:data], :custom => "chbh=6,2,0") %>
I did leave out the labels on the chart. Since I had so much data they were taking up way too much room. To add the labels you would just append :labels => @report.labels to the arguments in the bar method call.
Here is the final result.

It is pretty cool that Google provides us with the service free of charge. The downfall is that there is a daily limit of 50,000 charts that can be generated per site. I can’t think of anything that I have worked on that would exceed that number, but things can change. The other issue is that Google has control and at any time could discontinue supplying the service. Personally I can’t picture Google doing something like that, but anything can happen.
Although Google’s API and GoogleCharts make things pretty easy I hope this helps a couple of people.
Technorati Tags: charting, rubyonrails
Custom Validation Messages
8 errors prohibited this account from being saved
There were problems with the following fields:
…
Maybe it is just me, but having error messages like the above seems a little to artificial to me. Maybe rails has standard error messages like the following so everybody changes them, who knows.
One thing I found when searching for customized error formatters is that they would only accept one model object reference, ie, they would only allow for
error_messages_for(:account)
and not
error_messages_for(:account, :user)
which is odd seeing as the overridden method does allow for many models.
Below is a custom method that will allow us to deliver the message with more of a person to person flavour.
def error_messages_for(*object_names) messages = [] object_names.each do |object_name| object = instance_variable_get("@#{object_name}") if object && !object.errors.empty? object.errors.full_messages.each do |message| messages << %(<li>#{message}</li>) unless message =~ /is invalid/ end end end if messages.size > 0 content_tag(:div, content_tag(:h2, "Uh-oh! We have some invalid fields.") + content_tag(:ul, messages),:id => 'errors') end end
It will also prevent messages like “Users is invalid” (yes that is pluralized on purpose) that occur from having the validates_associated :user validator telling us that the associated model is invalid.
This isn’t groundbreaking, but I know I will be searching for this again sometime soon.
Skydiving
On a recent trip to Mexico I went skydiving for the first time and it was most amazing thing. I can honestly say that if I was a heroin junkie I would give it all up for a few skydives.
Here’s the video
Sky Diving from chris olsen on Vimeo.
