Subscribe to the MPC blog rss feed feed-icon-14x14
 

Representing Data With Gruff Bar Charts

Posted on 10:39PM on 11/06/2008
Tags: gruff, complainatron

I'm currently working on Complainatron on the side. It's a simple but fun application that allows anonymous bitching and complaining. People like to do that, right? It also attempts to capture geographical information from users and does various things with it - including using the geographical data to create bar charts. For this task, I use Gruff (created by Geoffrey Grosenbach), a nice ruby wrapper around RMagick/ImageMagick.

Gruff's homepage explains how to install it, so I won't go into much detail. Suffice it to say that you need ImageMagick, RMagick, and, obviously, Gruff.

Creating a bar chart

I've got data that is essentially a collection of ComplaintCategory objects. Each complaint category has a category name and the number of submissions against that category. What I want to do in the case of this example, is to create a bar chart like that shown below.

Popularity

Below is an example of how I could go about doing this (in the application, it's actually a lot more abstracted, but this works as an example).

Naturally, it's necessary to pass in options to let Gruff know how you want it to create the chart. As well, the data to chart needs to be present. Because I have a collection of ComplaintCategory objects, I can set the chart labels to an array the contains the category names. I can set the actual data for the chart to an array that contains the counts for each category.

On the whole, Gruff is easy to use and does a nice job. I wanted to post this information because although there are various examples using Gruff out there, there weren't too many discussing creating bar charts.

Hope someone finds it useful!

2 Comments (Show) (Comments are closed for this post)

RDefensio A Framework Agnostic Ruby Library For Defensio

Posted on 09:15PM on 10/29/2008
Tags: RDefensio, defensio

Yesterday, I posted about switching this blog over to Defensio. Today I'd like to look briefly at how I went about integrating it.

Defensio provides an API against which you can make HTTP posts. This is a pretty straightforward thing. I simply wrote a library that makes it a little less low-level.

The code is on GitHub, here.

The library is designed to be framework agnostic and to have as few dependencies as possible. The specs rely on RSpec, but that's about all that it requires.

Configuration

 

For any app, the first thing that needs to be done to use RDefensio is to configure it. You must have an API key from Defensio. This site is built with Sinatra, so I configure RDefensio within a Sinatra configure block:

The owner url is simply the url you registered with Defensio when you signed up. In my case, it's http://mattpayne.ca/blog

If you're using Rails, this could be done in an initializer.

That's all it takes to configure it.

Usage

 

Well, Defensio exposes several API methods that can be called. RDefensio mirrors them.

All of these methods return an OpenStruct object that represents the result of the post to Defensio.

The get_stats method is particularly useful if you want to display information about your Defensio interactions. It will return values for # of spam comments, # of false positives, # of false negatives and several other nice informational items

That's it for my post about RDefensio. It seems to be working well for me over the past few days.

0 Comments (Show) (Comments are closed for this post)

Keep Your Post Comments Spam Free With Defensio

Posted on 04:15AM on 10/29/2008
Tags: defensio

A few days ago, I talked about adding Akismet functionality to this blog on top of an existing captcha implementation. Ironically, there was a bug in the new code that prevented anyone from commenting! I guess that's one way to reduce comment spam.

The person that let me know about the problem was Carl Mercier, of Karabunga. Karabunga is a Canadian development shop near Montreal that has developed a spam filtering service called Defensio.

First and foremost, let me say that I don't get a lot of spam. I also don't get much traffic, so I guess that makes sense ;) Spam is still a concern to me though. I think it looks ugly and takes away from the real content.

I wasn't overly happy with my Akismet/captcha combination in the first place. The captcha is a bit of a hassle to read and many people dislike entering them. Plus, according to Carl, captchas are not terribly secure anymore as people are beginning to hire humans to solve them. I don't have any real issues with Akismet, but I wasn't entirely happy with my implementation of the two together. I decided that perhaps the entire commenting component of my blog should be rewritten - this time using Defensio.

Why Defensio? I'm not going to do a comparison with Akismet here; several folks have already done that here and here and, I'm sure, in many other places. Suffice it to say that I liked what I saw:

  • Defensio has the ability to learn. The more you work with it, the smarter it gets about you and what you believe to constitute spam.
  • It provides "spaminess" ratings for submitted comments.
  • It promotes transparency in terms of making people aware of how well you, as a blogger, are doing in combination with the Defensio service. I like that.
  • Defensio has a nice API.
  • Defensio is Canadian-made (have be a little patriotic after all).
There are a couple of things to keep in mind:
  • Defensio learns through your interactions with it, so initially it may not be too "smart".
  • There is a bit of comment maintenance to deal with since someone has to handle the ones that may or may not be spam.

Personally, I'd rather have more control than not enough.

It was a slow weekend, so I removed all of the captcha and Akismet functionality and replaced it with the new Defensio functionality.

As a result of this effort, I also created a framework agnostic Ruby library for accessing the Defensio API. I call it RDefensio. Why framework agnostic? I like framework agnostic code and I use Sinatra for this site. For the folks looking to incorporate Defensio into a big established framework like Rails or .NET, I suggest taking a look at Defensio's download page, here.

Anyway, that's it for now. Maybe a few comments would allow me to test the system ... ;)

0 Comments (Show) (Comments are closed for this post)

Incorporating Akismet

Posted on 03:25PM on 10/23/2008
Tags: Akismet, blog

I decided today that I wanted to incorporate Akismet functionality into this site. I do currently use Captchas as a way to ensure that only real comments get submitted, but Akismet seems to provide an extra layer of security. Plus, I was bored ;)

What is Akismet? According to the site:

"When a new comment, trackback, or pingback comes to your blog it is submitted to the Akismet web service which runs hundreds of tests on the comment and returns a thumbs up or thumbs down."

Pretty cool.

There are plenty of plugins and libraries for Akismet, but not one specifically for Sinatra, which is what this site is built on. I decided to use Ruby Akismet API, by David Czarnecki. It's a nice, simple, small library that does what I need. Basically, it posts data to the Akismet API and returns true if the comment has been evaluated as spam.

So my controller action looks more or less like this now:

  post "/blog/create/comment/:slug" do
    @post = Post.find_by_slug(params["slug"])
    raise_post_not_found(params["slug"]) unless @post
    @comment = Comment.new(params[:post])
    errors = @comment.validation_errors || []
    unless Captcha.valid?
      errors << "Invalid captcha. Please try again." 
    end
    unless AkismetWrapper.valid?(@comment, {
        :ip => user_ip, :referrer => user_referrer, :user_agent => user_agent}
      )
      errors << "Your comment appears to be spam. Please try again."
    end
    if errors.empty?
      @comment.save
      redirect "/blog"
    else
      @errors = errors.join("<br />")
      erb :new_comment
  end

I created a module called AkismetWrapper simply because I didn't want to use the Akismet API class directly from my controller code. Additionally, it'll help me with testing since I can just stub the method on the simple wrapper module.

So now I've got a dual layer of protection: Captchas and Akismet. Is it necessary? I don't know. Did I learn something from it? You bet! That's all I really set out to do anyway.

1 Comment (Show) (Comments are closed for this post)

Multiple Unobstrusive Onload Events Using Prototype in Ruby on Rails

Posted on 02:44PM on 10/06/2008
Tags: javascript, rails

I'm currently working on a web application in Ruby on Rails that has a high degree of client-side scripting requirements. In almost every view, many things need to take place just after the page loads. I'm using Prototype, but any good javascript framework will do.

Since the application has a large amount of forms to be filled in by users, almost every view needs to set focus on a textbox in the form. On top of this requirement, almost every view has other javascript-related requirements when a particular view loads. For example, several of the views need to be able to set the form to its previous state when reloaded.

The typical way of registering an OnLoad event looks something like:

//application.js
  window.onload = function() {
    setFocus();
  }

  function setFocus()
  {
     focusElement = getFocusElement();
     if(focusElement && focusElement.focus)
     {
        focusElement.focus();
     }
  }

  function getFocusElement()
  {
     $$('input.focus').first();
  }

This sets up a callback that, when the window is loaded, locates an input element with a class of 'focus' and calls focus on it. This works fine. I put this in my application.js file and load it with every view.

Now what about running additional OnLoad actions for specific views? I don't want to code everything in application.js. That approach has several problems. Firstly, it means that application.js gets really bloated and if it loads with every view, there is additional overhead. Secondly, it means that you may be loading a bunch of code, required for other views, that is not needed for the current view. Thirdly, some of the OnLoad code may expect certain elements to be on the page, and they won't always be there. The bottom line: this is not a good approach. So what is the solution?

For me (and you may have other, better solutions), the approach that works best is a combination of application.js and content_for in my views.

Firstly, I ensure that in my layout I include an addtional named yield in the head section of the HTML. For example:

<%= yield :head %>

This gives me a place to include additional javascript files. In my view, I can do

  <% content_for :head do %>
     <%= javascript_include_tag "user" %>
  <% end %>

In this, case, I would be adding a javascript file called user.js (located in public/javascripts) to the head section of this view.

That solves one problem: that of only loading javascript code appropriate to the view currently being rendered.

There is only one more problem to get past: In my application.js, I am registering an OnLoad handler (as show above). In my user.js file, I also need to register an OnLoad event handler. As it sits right now, whichever file gets loaded last will clobber all the previous OnLoad handler registrations. How can this be addressed?

My solution (and, I'm sure, others') is as follows:

  //application.js
  var onLoadHandlers = $A();

  window.onload = function() {
    onLoadHandlers.reverse();
    onLoadHandlers.each(function(method) {
       method();
    })
  }
  
  function registerOnLoadHandler(method) {
     onLoadHandlers.push(method)
  }

  registerOnLoadHandler(focusHandler);

  function focusHandler() {
    //as shown previously
  }

If application.js is loaded with every view, we can effectively ensure that it's possible to call registerOnLoadHandler from any other javascript file loaded after it.

As a result, in my user.js file, I can do the following:

  //user.js
  registerPageLoadHandler(setViewState);
  registerPageLoadHandler(roleChangedHandler);

  function roleChangedHandler() {
    //code
  }

  function setViewState() {
    //code
  }

These functions will also be run when the page is loaded.

I like this technique and it seems to work well. It minimizes the amount of javascript code that I need to load on a per page basis and ensures that only javascript required for a particular view is loaded for that view. I also think that it makes it very easy to find javascript code related to a particular view.

2 Comments (Show) (Comments are closed for this post)

More

1 2 3 4 5 6 7 8
Please note that I am currently unavailable for any large, long term work.