Archive for the ‘Programming’ Category

Jan 8

While working on a recent project at my job, I ran into a situation where I needed a form with a vertical column of checkboxes. At the top of them, I wanted to place a checkbox that when checked, would toggle the checkboxes below it.

Checkboxes

Checkboxes

I happen to be using a Rails app that has Prototype.js. The javascript to hook into the top-most checkbox and make it do our bidding looks something like this:

Event.observe(window, 'load', function() {
  var select_all_box = $('select_all_box');
  if (select_all_box) {
    var checkboxes = select_all_box.up('form').getInputs('checkbox');
    checkboxes.shift(); // throw out select all box
 
    select_all.observe('click', function() {
      checkboxes.each(function(e) {
        e.checked = select_all.checked;
      });
    });
  }
});

As you can see from the outer-most observe call, I’ve written this to be unobtrusive. With the page finished loading, we look for the checkbox we want to enhance. The HTML for the above screenshot is just a simple <table> contained within a <form>.  From there, grab all of the checkboxes in the form and then throw away the first one. Then create an event listener for the checkbox that iterates over the rest of the checkboxes matching them to the current state of the check-all box. Every time you check or uncheck the box at the top, all of the checkboxes below will follow.

Sep 2

Dear RA,

We’ve had some good times. You were my first and only authentication plugin. I’ll always remember you, but it’s time to move on. There’s this hot, young plugin on the block named AL that I’ve fallen for. So long. *tear*

Rick Olsen’s restful_authentication is out and Ben Johnson’s authlogic is in as the hot Ruby (and/or Rails) authentication module these days. No disrespect to Rick and restful_authentication. It’s got sound security principles behind it, but dealing with the implementation can be a headache. If you’re unfamiliar with restful_authentication, the first thing you would do after installing the plugin is run some generator scripts. These scripts create a bunch of code in your Rails project. Where that becomes a problem is if you have to modify the code and then later want to run the generator again.

Authlogic takes the stance that you should never have to run a generator. It also has a lot of auto-configuration (based on the fields found in your user model). Sessions in authlogic make use of the familiar, standard RESTful controller. The gem itself is also very well organized with things being broken down into modules. The only downside I’ve comes across is I can’t find a page to show me all of the configuration options at once; hardly something to pick on.

Instead of trying to write the be-all end-all guide, this will be more of a case study.  The nature of using a configurable generator, as restful_authentication provides, is that it would be tough to cover all cases. In addition, my app had some closely related components, such as password resetting, that needed to also be changed.

The first thing I did was install authlogic as a gem and pull it into my application. If you’ve spent any time with Rails 2.2 or higher, then this should be old hat for you by now.

sudo gem install authlogic

Then add the following to your config/environment.rb file:

config.gem 'authlogic'

In your user model, add the following:

acts_as_authentic do |c|
  c.transition_from_restful_authentication = true
end

With authlogic in place, you can remove restful_authentication. The plugin directory can be removed from vendor/plugins. You will also need to remove the lib/authenticated_system.rb and lib/authenticated_test_helper.rb files as well as the includes for them. These should be in application_controller.rb and test_helper.rb respectively if you followed restful_authentication’s instructions.

From here, a number of things still need to happen and it doesn’t much matter the order. There need to be some database changes to the users table. A controller for sessions needs to be added or an existing one needs to be modified. The test suite will be severely broken with a large number of tests failing or generating errors. There is also a lot of code to clean up in the user model and controller. As mentioned earlier, there may also be some related pieces which need clean up or conversion such as password resets.

What I ended up doing was half-following Ben Johnson’s guide for setting up Authlogic and adapting it to the existing code. In this process I stripped out all of the generated code from the user model and controller, generated a transition migration, and copied a few views for the users_controller.rb from the sample application.

The sessions_controller from restful_authentication could be modified, however, I found it easier to start from scratch. I copied the controller and views from the authlogic setup guide and made some small changes to the views to adapt them to my layout. You will also need the following model at minimum:

class UserSession < Authlogic::Session::Base
end

Because you inherit from Authlogic::Session::Base, there is no actual code in the session model. Some people like to work with the session variables through a model, you can add this code if you’d like but the default should get you all you need to begin.

A popular feature to add to any authentication system is a method to request a forgotten password. Ben also provides a guide for how to handle this with authlogic. As with the sessions, password resets were a concise and contained component. It was easier to wipe out what was existing and start fresh with the aforementioned guide.

Authlogic follows Rails’ convention over configuration idea and will pick up functionality based on the fields that exist in your model. Of course this means changes to the database and in Rails, that means a migration. Below is what mine looks like:

class TransitionToAuthlogic < ActiveRecord::Migration
 
  def self.up
    change_column :users, :crypted_password, :string, :limit => 128, :null => false, :default => ""
    change_column :users, :salt, :string, :limit => 128, :null => false, :default => ""
 
    rename_column :users, :salt, :password_salt
    rename_column :users, :activation_code, :old_activation_code
    rename_column :users, :password_reset_code, :old_password_reset_code
    rename_column :users, :remember_token, :old_remember_token
    rename_column :users, :remember_token_expires_at, :old_remember_token_expires_at
 
    add_column :users, :login_count, :integer, :null => false, :default => 0
    add_column :users, :failed_login_count, :integer, :null => false, :default => 0
    add_column :users, :last_request_at, :datetime
    add_column :users, :current_login_at, :datetime
    add_column :users, :last_login_at, :datetime
    add_column :users, :current_login_ip, :string
    add_column :users, :last_login_ip, :string
 
    add_column :users, :persistence_token, :string, :null => false
    add_column :users, :single_access_token, :string, :null => false
    add_column :users, :perishable_token, :string, :null => false
 
    add_column :users, :active, :boolean, :default => false, :null => false
 
    # set active users to active.
    User.update_all("active = 1", "state = 'active'")
 
    add_index :users, :perishable_token
  end
 
  def self.down
    remove_column :users, :active
    remove_column :users, :perishable_token
    remove_column :users, :single_access_token
    remove_column :users, :persistence_token
    remove_column :users, :last_login_ip
    remove_column :users, :current_login_ip
    remove_column :users, :last_login_at
    remove_column :users, :current_login_at
    remove_column :users, :last_request_at
    remove_column :users, :failed_login_count
    remove_column :users, :login_count
 
    rename_column :users, :password_salt, :salt
    rename_column :users, :old_activation_code, :activation_code
    rename_column :users, :old_password_reset_code, :password_reset_code
    rename_column :users, :old_remember_token, :remember_token
    rename_column :users, :old_remember_token_expires_at, :remember_token_expires_at
  end
end

Most important are the two change_column calls at the top. Authlogic needs 128 characters to store the crypted_password and salt fields whereas restful_authentication only provides 40. It doesn't really matter if they are still 128 characters when the migration is run down so I didn't bother changing them back. Besides, you'd never do that in production anyway.

As mentioned previously, there is an active column being added to the user model. Restful_authentication has an option to enable user states. This is done to allow tracking of activation. Authlogic doesn't come with anything such as this built in. It's simple enough to add and someone has written a tutorial already. The migration handles carrying the active status over from restful_authentication with a single update_all call.

Notice the rename_columns; the idea is that those columns are essentially flagged for later removal. This is a somewhat cautious approach. It would be possible to handle the removal of these columns in a later transaction.

The final piece to the puzzle is making your test suite happy again. If you are at all serious about testing, you will now have a number of failing tests after making such widespread changes to your application. In my application, much of the functional testing involved logging in user with a specific role. To do this in authlogic is simple.

First, add support for authlogic in tests by requiring the authlogic test module in test_helper.rb.

require 'authlogic/test_case'

Then, add the following to any functional or integration test you need to log in to test:

setup :activate_authlogic

Finally, you can initiate the actual login by calling UserSession.create and passing in your user object like so:

assert UserSession.create(users(:admin))

Notice we can even assert that the result of this login is true so we know it actually happens. The example happens to pass in a user from a fixture, but you could just as easily use a factory to generate your user object. Authlogic doesn't care where the user comes from.

Assuming all of your tests pass and you've done enough manual testing to be satisfied, you can go ahead and declare your switch from restful_authentication to authlogic complete. Changing over to a new authentication module can be a scary thing, especially when you are changing encryption methods for your passwords. It has the potential to lock out every single user in your system if you get something wrong. Remember, TATFT. A solid test suite and thorough manual testing will give you confidence when it comes to launching this into production with your application. If you do your due diligence, your transition will be smooth.

I created this post based on the work I did for DecoyMusic.com. It is now happily chugging along on Authlogic. Now that the transition is done, it's time to start using authlogic's plugin architecture to add OpenID and Facebook Connect support.

Jun 2

Don’t Be a Douche

Posted: 11:06AM Tagged: Programming, Rails, Technology

If you’ve got a great idea for the next big web framework, the first thing you should do is not write a douche-y blog post bashing other web frameworks. Here’s some ideas for things you could do instead:

  • You could make a website promoting the advantages of your framework over other existing frameworks.
  • You could improve the framework itself.
  • You could document the framework so that others can easily begin using it.

The point is by attacking others, you don’t accomplish anything other than branding yourself as a grade A asshole. It’s fine if programming in C and doing all that memory allocation, dealing with pointers, and calling functions validates your skill as a programmer. I happen to like Ruby because I don’t have to do those things. What’s great is that we can co-exist. You can have your fast framework written in C and serve thousands of pages a second. I’ll stick to my ’slow’ framework written in Ruby. Chances are the people visiting the sites will never know the difference anyway.

Drop the ego. Realize that there can be more than one approach to solving a problem and yours isn’t always going to be the best one.

May 9

It seems that the Rails core team is so busy building awesomeness into Rails that they don’t have much time to improve the documentation. This is why docrails was started. The new Rails Guides are immensely helpful, and quite the improvement over the old wiki. However, you’ll still find a few surprises if you dig around in other people’s code like this handy feature I’ve found in ActionMailer.

ActionMailer let’s you specify the from address on emails sent out, but did you know you could also set a nice name in addition to that? You might have a basic mailer method like this.

  def my_email(to_email, to_name)
    from 'myname@example.com'
    recipients to_email
    subject "Hello There #{to_name}"
    body(:to_email => to_email, :to_name => to_name)
  end

We pass in an email address to send to and the person’s name. The from name is simply hardcoded as a string. If that email showed up in your inbox, it would probably say it’s from myname. Depending on the email client, it may just show the address it came from. That’s great, but it doesn’t look very nice.

Enter the undocumented syntax I’ve stumbled on.

  def my_email(to_email, to_name)
    from 'My Pretty Name <myname @example.com>'
    recipients to_email
    subject "Hello There #{to_name}"
    body(:to_email => to_email, :to_name => to_name)
  end</myname>

All you need to do is add the name you want to appear in the from field before your email address, then add a space, and finally wrap the email with angle brackets. That’s it! Now when your email arrives in someone’s inbox, it will show that it’s from My Pretty Name.

The syntax leaves a bit to be desired in my opinion. It doesn’t feel very Rails-y or even like the rest of ActionMailer. When specifying the recipients in ActionMailer for example, you can pass in either a single email address as a string or an array of string email addresses. The syntax should be similar with the from name and address. Here’s my proposed syntax.

  def my_email(to_email, to_name)
    from ['My Pretty Name', 'myname@example.com']
    recipients to_email
    subject "Hello There #{to_name}"
    body(:to_email => to_email, :to_name => to_name)
  end

Seems like a logical addition, eh? Pass in the from name as the first item in an array and the email as the second. Using a hash instead would also be acceptable. Maybe I’ll dig into Rails and submit my first ever patch.

Apr 23

Camping in the Cloud

Posted: 12:04PM Tagged: Programming, Technology
Cloud Camp Minneapolis

Cloud Camp Minneapolis

No, I wasn’t in a tent somehwere near St. Cloud last weekend. I was at Cloud Camp Minneapolis; a regional unconference on the emerging number of cloud computing possibilities that are poised to change the way we think about computers. In layman’s terms that means a bunch of local geeks and a few vendors got together to talk shop in a roughly structured conference format. There have been many such dates around the world.

The first interesting thing about this conference was that without Twitter, it never would’ve happened for me. In the middle of last week, I saw some talk of it in Twitter and checked out the event listing. Unfortunately all 100 seats were full and so was the waiting list. I didn’t even bother with the 2nd waiting list as I figured there was no way I was getting in. Instead, I said something on Twitter and what happened next I never expected. The local organizer, @georgereese, must have been monitoring #cloudcampmsp because he said I was all clear to come. That’s putting social networking to use.

I arrived to the U of M campus and made my way to the building. There were bagels, fruit, coffee, and juice for everyone to snack on. I grabbed a little cup of coffee and ended up talking to a guy who called himself “Danalytics”. He runs does consulting work. We talked about cameras, phones, and the Internet. I didn’t really see him the rest of the day, but he was nice to talk to.

Cloud Camp Breakfast Social

Cloud Camp Breakfast Social

With everyone fed, people began going into the lecture hall for the opening presentaions. This was really the only structured part of the conference. Each of the vendors gave what amounted to a 5 minute pitch for what they are doing with cloud computing. enStratus, Visi, aServer, RightScale, Microsoft, and Rackspace all were present. I liked the brevity of the talks. The 5 limit was indeed a hard limit.

Matt Tanase of Slicehost/Rackspace

Matt Tanase of Slicehost/Rackspace

Twitter and TweetDeck for monitoring the #cloudcampmsp hashtag were indispensable tools. It was interesting to see the reactions from the crowd in real time. Especially when you had these companies talking about their products. You could tell when they were talking BS because the backchannel chatter would pick up. At one point, the moderator pulled a question from the backchannel to ask the entire group. You can’t tell me Twitter is useless and expect me to believe you after what I witnessed last weekend. Can we all get over that now?

Following the vendor lightning talks was a panel comprised of the following gentlemen:

George Reese – enStratus
Jason Baker – Visi
Graeme Thickens – Tech ~ Surf ~ Blog
Jeff Brand – Microsoft
Curtis Thompson – Best Buy Contractor

Opening Panel

Opening Panel (L to R: Thickens, Baker, Brand, Thompson, Reese)

The purpose of this panel was to spark topics for the rest of the day. There were already some talks planned such one focusing on Curtis’ work on Best Buy’s GiftTag and their use of Google App Engine. Things began with with a discussion of why the group came together that day to talk about the cloud. The general consensus was that cloud computing is easy, cheap, powerful, and there is sort of a technolust around it right now.

From there the discussion steered towards the market or audience for cloud computing. The types of business that could benefit from it most are small to medium business. SMB’s generally don’t have the knowhow, infrastructure, or capital to have a large datacenter. Hosting in the cloud means they can try out things cheaply and grow the products later if there is promise.

We later moved into sort of a pros and cons discussion of cloud computing versus keeping resources in house. Things generally came out in favor of the cloud though. In house servers can be run into the ground and therefore you get your money’s worth out of them, but doing things in the cloud is cheap and you don’t have to pay people to run your servers and infrastructure. You just have to pay someone to maintain your cloud. There are also other costs such as bandwidth and HVAC that you don’t have to worry about with the cloud.

There was some brief talk of security, but it quickly became apparent how large the topic was and it was relegated to a session later in the day.

The panel discussions wrapped up with some talk of vendor lock-in and the existence of free cloud resources. Uri Budnik of RightScale was quick to jump in and promote his company’s template model for cloud hosting. They allow you to move things from GoGrid, to EC2, to Rackspace easily without the need to worry about what setup needs to happen on those services. This could be a bigger issue moving forward.

Uri Budnik of RightScale

Uri Budnik of RightScale

The nonprofit talk was also sort of squashed in favor of more in depth discussion during an afternoon session. I think it got relegated to the SMB session.

During lunch (which was provided free!), I met up with @staticnullvoid and @jostheim. It was nice to kick back and chat with those two. I don’t often find people I can have conversations about technology and not have to explain everything or ask if they’ve heard of it.

Afternoon sessions

Afternoon sessions

My first afternoon session of the afternoon was a case study of Google App Engine by a couple of guys who worked on Best Buy’s GiftTag application (slides). The session was led by Curtis Thompson (@iffius) and Thomas Bohmbach (@gumptionthomas). The fact that those two are contractors and kind of operate as rogue employees within Best Buy is interesting and probably worthy of a blog post itself. I’ll leave that for another day though.

Curtis and Thomas say that GiftTag is a “gift registry that doesn’t suck.” You aren’t restricted to only placing items from Best Buy on it. You can take things from around the web and pull them in.

The application started out being hosted on Slicehost, but after Google App Engine launched they thought that it would be perfect to try out. When on Slicehost, they were using Drupal and MySQL. In 3 weeks, they were able to rewrite the entire GiftTag app for Google App Engine and BigTable (Google’s storage solution).

Google App Engine provided them the ability to get the app running and try it out. They weren’t worried about scaling the application later. They just knew it would work. They can do things like push new versions and restart the app without any downtime. Deployments themselves are versioned. You can deploy a staging release and demo it before launching the changes on your live site. There are GUI applications for deployment and they are really “one click deploys.”

There are also some challenges to working with Google App Engine. The most glaring of those is that BigTable is not a relational database. Doing a count of records is not possible and you are limited to 5000 results returned. There are ways to code around this. Make your interface better. For example, instead of pagination displaying individual page numbers, just allow prev, next, beginning, and end. This is how Gmail and Google Docs work. Google’s “search culture” probably brought this about. Search becomes very important if you can’t browse through data.

The best part about Google App Engine is that it is free unless you get really big. You can try things out on it with the only investment being time. With the addition of Java as a supported language, it opens up so many other languages. Any language that runs on top of the JVM should be available for use on Google App Engine. This makes it a very attractive resource.

The second afternoon session I attended was about security and liabilities of putting data and services in the cloud. It was moderated by Jim Hanlon. I have to admit, I wasn’t as engrossed in this talk as I was with the events from the rest of the day. Most of the people seemed to be from larger businesses that had concerns about putting sensitive data in the cloud. I’m not saying these people didn’t have legitimate questions, that’s just not something I have to deal with.

The biggest takeaway from this session was that the question of where data is and who has (or has had) access to it becomes very hard to answer. Even someone like me who doesn’t have sensitive data concerns could be affected by an over-reaching goverment raid.

CloudCamp Minneapolis was a success. There were a few connections I made and some interesting topics to think about going forward. I also had a chance to use my camera which I hadn’t done in awhile. Hopefully more events like this take place in the Twin Cities.

Mar 24

 

I have some work to do.

I have some work to do.

Last week, Microsoft officially lifted the covers off of Internet Explorer 8.0 and deemed it ready for public consumption. According to a post on Neowin.net, the browser will be available via Windows Update as early as April 13th and as an Automatic Update as early as April 27th. Of course, you could also grab it right now if you wanted.

One of the key features that had developers like myself salivating was better standards compliance. Specifically with the CSS standard. The closer we can get all browsers to following standards, the easier it gets to create a website that looks right in all browsers without resorting to hacks and tricks. Unfortunately even the tried and true methods of targeting IE browsers in the past was made more difficult by a new feature, Compatibility View.

Windows Internet Explorer 8 improves browser interoperability and advances the Web by delivering a better implementation of web standards. Although this is a move in the right direction, you might encounter compatibility issues with some sites that still rely on the behavior of earlier versions of Internet Explorer. Common symptoms of site compatibility problems are out-of-place menus, images, or text.

Compatibility View resolves most site compatibility issues and makes websites that are designed for older browsers look better.
From: Release Notes for Internet Explorer 8

If you’d read only that, you’d think that Microsoft is doing the right thing. They’re helping website developers out by supporting more standards and they’re helping out “Joe the Computer User” with this Compatibility View feature. However, the devil is in the details.

Compatibilitiy View

The way Compatibility View works is like this. By default, IE8 will render in standards mode. This is good because as I said, it lets website developers code to the standards and not worry about whether or not things will work. They just do. If a consumer comes to a site that they don’t feel looks like it was intended, they can toggle Compatibility View for that site. What Compatibility View is actually doing is using a non-standards compliant rendering engine that is similar to IE7 to render the page instead. I say similar because it’s not the same as viewing a page in IE7 (yet another headache for developers). Furthermore, if a sufficient number of people use Compatibility View on a site, it will be added to an internal list on a server somewhere at Microsoft.

There are several problems with this. First of all, the fact that Compatibility View renders things almost like IE7, but not quite is a real problem. As far as I know, there is no way to query which mode the browser is in. Conditional comments targeted at IE7 won’t be picked up with Compatibility Mode.

Worse yet, a site that gets on the Compatibility View list has no way of taking themselves off the list. You are forever cast off into non-standards land for any Internet Explorer 8 user. If you update your site to fix whatever rendering issues there were formerly in IE8, there is no way to tell Microsoft that. Until Microsoft comes up with a way for site owners to have their site taken off the list, your site will be broken in IE8 (should you eventually update it).

In all likelihood, we developers have a few months before IE8 starts to gain any sort of market share. If you haven’t at least got a test box or VM with IE8 installed on it yet, then it’s time to get going. With any luck, some smart people will figure out how to deal with a lot of the mess IE8 has introduced and the web will move along. From a consumer point of view, IE8 is a welcome upgrade to IE7 touting better security and faster rendering. It’s too bad it has to make so many of us lose our hair. All the more reason to Bring Down IE6.