Garbage Burrito

Blog

Ben Kittrell - 01/19/2010 22:05:00
Comments: 0

For awhile I had a Javascript bot blocker that did a good job keeping spammers from flinging crap at our blogs, but apparently they got smarter. Go Figure. Even though I hate them, I figured the best option would be to add a Captcha system. I looked into systems like Snook and Askimet and really didn't think they were right for our customers at this point. At least not for a first line of defense.

Before you get much further, this is not a plugin, and I'm not even going to provide full examples. One of the chief benefits of a custom system is the obscurity. However, I do think the general approach is sound and worth sharing. IMO, creating a captcha plugin is kind of like selling every lock with the same key.

I looked at hosted solutions like Re-Captcha, but didn't want to be reliant on a third party. I also looked at the Simple Captcha Rails plugin. The problem I had with it is that it generated the images on the fly, which seemed like it could turn into a resource nightmare with all the requests we get.

I wanted to create a system that used static pre-generated images so it would be super fast.

The Gist of It

I generated a set of images using ImageMagick. Here's an example of the code I used to do that...

words = %w{ sack river space }
for word in words
`convert xc:#FFF -resize 110x35! -frame '1x1' -family Helvetica -pointsize 13 -gravity "Center" -draw "text 0,0 '#{word}'" #{word}.jpg`
end

Notice the text is the name of the file. I put those images in a directory in my app. Then I created a table with a key, filename, and created date.

Here's some psuedo code.

image = getRandomCaptchaFile()

captcha = findCaptcha(filename = image, createdDate > expireInterval)

if captcha == nil
captcha = new Captcha
captcha.filename = image
captcha.key = getRandomKey()
captcha.created_date = now()
captcha.save
end deleteAllCaptchas(created_date < 1.day.ago) return captcha

This is the crux of the system. Basically I get a random image file, check to see if a captcha record has been created within a set interval, if not create a new one with a new key (such as a GUID), and delete all the old captchas. For doodlekit I also have some code to take into account the multi-site environment.

Once you have this you can create a controller or action to accept the random key. This will look up the image from the captcha table and return the image data. The random key breaks the link between the URL and the actual image.

Comments: 0
Comments: 0

First of all, if you're not using will_paginate for all of your pagination then you should be. It's well known that the built in pagination in Rails is slow and clunky. will_paginate will easily replace your ActiveRecord pagination, but it can paginate just about anything else.

John Nunemaker's Twitter Plugin makes short work of hooking your app up to the Twitter API. With a few strokes of code you can be pulling statuses down like mad. Now if you want to list a bunch of statuses you'll likely want to have some kind of pagination.

First there's the standard Auth

httpauth = Twitter::HTTPAuth.new(username, password)
client = Twitter::Base.new(httpauth)

Then setup some pagination defaults, and grab some tweets.

current_page = params[:page] || 1
per_page = 100
tweets = client.user_timeline(:count => per_page, :page => current_page)

Then just wrap the paginator around your collection and the deed is done.

if !tweets.empty?
@tweets = WillPaginate::Collection.create(current_page, per_page, tweets.first.user.statuses_count) do |pager|
pager.replace(tweets)
end
end

Finally, insert the pagination links in the view.

<%= will_paginate @tweets %>

That's it. A marriage of two great plugins indeed.

 

Comments: 0
Comments: 0

Plumber or Serial Killer?  You decide.When people find out I've been renovating my house for 7 years they always ask, "where did you learn how to do all that stuff?"  The truth is that I learned it all as I was doing it.  I've replaced copper and PVC plumbing, run gas lines, rebuilt door and window frames, installed kitchen cabinets, sinks and countertops, dry walled, floored, painted, electrified as well as many other things I had no idea how to do before we moved in.  It's not because I'm a super awesome dude, it's because I shed my fear of learning new things.

When you think about it, companies make products that are easy to use.  Just because you're a professional plumber doesn't mean you want to spend hours putting together an unnecessarily complex system.   Sure there are things best left to the professionals.  I wasn't about to rent a backhoe and dig up my own sewer line, or get up on 30 foot scaffolding to hang siding.

I constantly think about this in my career.  Sometimes I avoid adding a new feature, or trying a new tool because I'm afraid that it will be too complicated or take too much time.  This reminds me of when XML was just a buzzword.  For a long time I just heard descriptions of it and I was so afraid that it was some crazy complex system that I would never understand.  Then when I actually saw what they were talking about I was like "That's it?!".

Most things in this world are much more simple than they look from the outside.  If you just jump in, it's really not too bad.

Comments: 0
Comments: 0

I recently got the E-Mail Marketing itch. I realized we have a great email list that we haven't tapped into at all. The thing is I don't want to just blast the same email to everyone, I want the email to be semi-intelligent, ie. 2 days after someone signs up they get an email with helpful tips.

Enter Mad Mimi's new Mailer API. This is just brilliant IMO, exactly what I was looking for. Basically they have a simple API to send out one-off or "Transactional" emails through their system. What are the benefits?

  • Create Beautiful E-Mails through their awesome promotion builder
  • Track Views, Clicks, Bounces, etc.
  • Automatically adds new E-Mails to your audience for other promotions
  • Ability to change your emails live, without deploying
  • Offload Mail Server resources to their systems

Now when a customer signs up, or their credit card is declined or whatever, instead of getting dry ugly text they get a rich friendly looking email. Plus I can track what's happening and improve the emails as time goes by.

I can also create a system where I choose when to send other promotions based on the user's behavior. This sort of personalized response is the best way to get through with E-Mail Marketing these days.

It's not necessary to go into a full-tutorial here, simply because Mad Mimi's developer center covers it well, and it's not that complicated in the first place. But I will cover the basics.

First install the gem. Make sure you've added github to your list of gem repositories.

$ gem sources -a http://gems.github.com (you only have to do this once)
$ sudo gem install mad_mimi_mailer

I had a version conflict with ActiveSupport so I froze the gem, but that's up to you.

What they've done is extend ActionMailer, so changing your emails to Mad Mimi is stupid simple. Essentially you put in your api creds, change the base class and add mimi_ to the front of all the methods. You'll also need to specify the name of the promotion.

MadMimiMailer.api_settings = {
:username => 'ben@doodlekit.com',
:api_key => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
} class BillerMailer < MadMimiMailer def mimi_suspended(customer_site)
settings = SystemSetting.find(:first)
promotion "Account Suspended"
@subject = 'Doodlekit Alert - Your Website Has Been Suspended'
@body = {}
@recipients = customer_site.email_address
@from = settings.admin_email @body[:customer_name] = customer_site.full_name
@body[:site_title] = customer_site.site_name
@body[:site_url] = customer_site.url
end

This mailer is using a promotion called "Account Suspended", so there must be a promotion with that name in my Mad Mimi account. The elements in the @body hash are mapped to variables in your Mad Mimi Promotion. :customer_name maps to {customer_name}.

Then just change your deliver call to include mimi_

BillerMailer.deliver_mimi_suspended(customer_site)

That's it!

One quick helpful tip. If your having issues and would like to see what's going on between you and the API you can enable HTTP debugging by adding the following line in the post_request method in mad_mimi_mailer.rb.

http.set_debug_output $stdout

Kind of Hackish, but good if you're in a bind.

I'm super happy about how this turned out, and plan to explore the other area's of Mad Mimi's API. And of course it's always great for sending out regular promotions to your email list.

Comments: 0
Comments: 0

Tried starting my development environement after installing Snow Leopard and got this error about the MySql gem not being included with Rails anymore.

!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.

Tried to install the gem and got this.

ERROR: Error installing mysql:
ERROR: Failed to build gem native extension.
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/ruby.h

Found a post that said to install the latest 64-bit MySql, got the same error. Found this thread that said to install XCode from the Snow Leopard disk and run this command and we're back in business.

sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

 

Comments: 0
powered by Doodlekit™ Free Website Builder by Doodlebit™ Website Company