Thursday, December 24, 2009

PuTTY with Ubuntu 9.10 and password less connections

A good friend of mine said I was not an advanced Linux user.  (He is.)  He was being kind to say the least as I consider myself somewhere between novice and intermediate if there is such a place. Compared to him I'm definitely novice. I was just struggling with a Linux server administration task today.  I was trying to secure my new VPS following Linode documentation (BTW, Linode has been great so far) for "Basic" security and ran into a bit of a snag while trying to lock down my use of SSH.  The trouble I ran into was with using RSA keys to authenticate my SSH connection with the server.  I wanted to disable the password option and setup SSH to use a public / private key pair.  The Linode documentation was helpful to a point but because I'm a Windows user it suggested that I use the PuTTY utilities to generate my keys and upload to the server.  Unfortunately I kept getting the message:

"No supported authentication methods available"

The documentation on PuTTY wasn't helpful and after several searches turned up a lot of wrong answers I finally found a post that suggested that Ubuntu 9.10 uses OpenSSH which relies on OpenSSL and that something was wrong or incompatible with that OpenSSL and would cause PuTTY problems. (I can't find the post again to reference, sorry) I turned on logging in PuTTY to see what I could see and sure enough, OpenSSH is being used.  I suppose there is a way to know that by looking on the server.  Going with that assumption I decided to generate the keys on the server and then download the private key for use with PuTTY on my Windows box.  Turns out that when I opened the id_rsa private key file with PuttyGen it was able to convert it to the "PuTTY" format for the file.  Couple seconds later I loaded into PageAnt and viola I was connecting to my server via SSH without using a password.

Moral of this story.  If you're using PuTTY to connect from Windows to an Ubuntu 9.10 server be sure to generate your keys on the server to save yourself some time and frustration.

References
Basic Security Settings (Linode Docs)
Linode VPS Hosting

Tuesday, December 22, 2009

Where to host my rails applications?

If you're like me and just making the switch to developing applications with Ruby on Rails then you've probably been asking yourself where can I host my app? I've spent some time over the last month researching hosting and in particular hosting for Rails applications. I have come to the conclusion there are a number of really good choices out there. I might even say there are too many choices which lead to this decision being drawn out a bit.

Here are the hosting choices I found that are available and "friendly" towards Rails application hosting.

  • Sustainable Websites - I listed this ONLY because it's a "Green" hosting provider.  I think it's cool that this hosting service powers it's servers off wind.  Unfortunately, it doesn't give me enough control and feel a bit like the GoDaddy offering on the surface.
  • Blue Box Group - Good virtual server choice here. The footprint I was looking at was $50 a month for 512MB RAM and 10GB disk space.  This service has off-site remote backup included.
  • slicehost - This one at first glance was in the right ball park.  A virtual server for $38 a month that has 512MB RAM, 20GB storage, and 200GB bandwidth allowance.  Automated backup service is available but costs extra.
  • Rack Space Cloud - This is a pay by the hour service.  The monthly cost was around $21.90 for the 512MB,20GB option but then I would need to add bandwidth charges.  They have a calculator you can use to guess at your monthly cost.  You'll need to know how much bandwidth you expect to use. Using the 200GB as a ceiling for the other plans I'm looking at this cost came out to around $58.90 a month.
  • RailsPlayground.com - Again, another good option and the cost for the virtual server I think I need 512MB/20GB/200GB would be around $38.00 a month
  • Linode.com - This provider doesn't offer a 256MB option.  They start at 360MB as a minimum with 360MB/16GB/200GB for $20 a month.   The 512MB/24GB/300GB option is $30 a month.  They don't have a backup option yet but claim to be working on it.
  • HostingRails.com - Not quite as easy to see what your cost per month will be on this site. If I understand the price matrix it looks like around $30 a month but bandwidth isn't as generous as the other providers.  They do offer a pay as you go plan which could be a cheap way to go.
  • heroku.com - One of the most interesting options.  You should check this out just to see what's possible.  If you need high availability in your solution then you might stop here if the cost doesn't scare you away.  They have an intro level free option where you can try things out.
Unfortunately, all of these seem to be good choices but obviously that will depend on your criteria. I was most concerned with balancing cost with performance. The first application I need to host will likely have low bandwidth requirements but I wanted hosting environment that would be easily expanded. I also am a bit of a control freak when it comes to putting my application and users at the mercy of automated and locked down "user friendly" hosting like GoDaddy and the like. (Notice that's not on the list above?)  Here's my short list of criteria for a hosting solution:
  1. To bring the balance to the cost part of my equation I was looking for as close to a fixed cost as possible.  Ideally as close to $20 - $25 a month as possible. 
  2. I want SSH access with out of band console access too.
  3. Starting out Ideally I wanted 512MB of RAM with a reasonable amount of disk space.  I have to have more than 256MB of RAM.
  4. A way to easily migrate/expand my hosting to have additional capacity.  I care if it's easy but the solution doesn't have to be a click of a button.
  5. I wanted an easy way to perform backups.
For me, this short list of criteria eliminated most of the list above on the first pass.  If you're criteria is different then you will want to dig a bit into each of the options above because they all have something good to offer.  I quickly narrowed the list down to three providers:  slicehost.com, linode.com, and Rack Space Cloud. 


I connected with the FAQ and "Why Me" pages on both slicehost.com and linode.com.  Found myself leaning towards those solutions almost immediately.  The Rack Space Cloud option could actually be the cheapest starting point of all three but only if my bandwidth stays low. (And who wants or expects that?)   Of the three I'm going to start with Linode.com and it's a good possibly I'll stay there until I have reason to move.  They seem to be the middle of the road for me.  They don't have the backup solution like slicehost.com but the ample disk space should allow me to manage that for a while.  To top it off a recent performance benchmark has added some emphasis to my choice.


I'd like to hear others experiences from using any hosting provider.  Leave me a comment if you have something I should be considering with my choice.

Thursday, December 3, 2009

Rails Country and States Fields Made Easy

I've been writing Ruby code for just over a year now. It never ceases to amaze me how a fresh perspective can really put you on the right track sometimes. The Ruby programming language has been that kind of fresh perspective for me. Still, at times you have to tackle the same old problem once again. That's what happened to me when it came time to create the dreaded country and state combo box code once again. It seems I've written this code at least a dozen times in the last 24 years of creating applications. Sometimes it's been for client desktop applications and sometimes for web based but it is always the same and always boring. Not so this time! Even if I had to write it myself, which I started to do, it was going to be new because I'm still learning Rails and at this point loving it. Yes, I know, can you say MVC framework? I can but this one's in Ruby! What a difference. I'm off my soap box now.

If you need to a country and state solution for Rails and you've used Google to find some information and examples you know this topic has been beat to death. I almost gave up and started to have some fun writing it all myself. (You know, that dreaded pull the ISO table from somewhere online and create the SQL inserts followed by JavaScript and some…. (You get the picture). Then I stumbled across a Railscasts episode #88 and a GitHub project called Carmen and voila! My solution came together quickly. New and fresh yet still the same old thing.

Here's how you get this going.

First watch the Railscast episode #88. Way to go Ryan Bates! (RailsCasts has been a life saver this year.)

I decided to implement the dynamic JavaScript exactly like Ryan shows. However, I did have to change his JavaScript slightly for a number of reasons. These are my changes:

#dynamic_states.js.erb

var states = new Array();
<% for state in @states -%>
  states.push(new Array("<%= state[0] -%>", "<%=h state[1] -%>", "<%= state[2] -%>"));
<% end -%>

function countrySelected() {
  country_id = $('<%= @country_dom_id %>').getValue();
  options = $('<%= @state_dom_id %>').options;
  
  indx = $('<%= @state_dom_id %>').selectedIndex;
  if (indx > 0 && indx < options.length) {
      curr_value = options[indx].value
  } else {
      curr_value = ''
  }
  options.length = 0;
  options[options.length] = new Option("Select a State","")
  states.each(function(state) {
    if (state[0] == country_id) {
      opt = new Option(state[1], state[2]);
      if (state[2] == curr_value) {
        opt.selected = true
      }
      options[options.length] = opt
    }
  });
  if (options.length == 1) {
    $('<%= @state_parent_dom_id %>').hide();
  } else {
    $('<%= @state_parent_dom_id %>').show();
  }
}

document.observe('dom:loaded', function() {
  countrySelected();
  $('<%= @country_dom_id %>').observe('change', countrySelected);
});

I needed to change the code that pushes the values on the states[] array. My values are coming from an array and they'll be string data as you'll see from the Carmen project later on.

I also needed to fix it so that if I supplied a selected value for the State list it wouldn't get stepped on by the JavaScript immediately calling the countrySelected()method. This was something Ryan added after the episode was produced (see his show notes) which sets up the fields properly the first time.

And last, I needed to supply DOM ids for my fields and because I have two models that have state and country values. I know this is not very DRY but it is what I have for now and I'm certain to re-factor it soon.

Next, take a trip over to the Carmen project on GitHub (thanks Jim, next time I'm in Chicago I owe you a beer) for a simple file system based approach to the Country and State data you'll need. It's actually nice not having to maintain the DB tables for this again. I might re-think that later but for the project I'm on right now this is just perfect. I stuck this in my vendor/plugins folder for the project I'm working on and then changed my view and the Javascripts_Controller class. Here's the code:

#Javascripts_Controller.rb

class JavascriptsController < ApplicationController
    def dynamic_states_for_user
        @states = getStatesArray
        @country_dom_id = 'user_country'
        @state_dom_id = 'user_state'
        @state_parent_dom_id = 'state_field'
        render :action => 'dynamic_states'
    end

    def dynamic_states_for_contact
        @states = getStatesArray
        @country_dom_id = 'contact_country'
        @state_dom_id = 'contact_state'
        @state_parent_dom_id = 'state_field'
        render :action => 'dynamic_states'
    end

    private 
    def getStatesArray
        @states = Array.new
        Carmen::STATES.each do |country|
            id = country[0]
            list = country[1]
            list.each do |state|
                @states.push([id, state[0], state[1]])
            end
        end
        return @states
    end
end
I simply built an array for the @states variable from the Carmen::STATES data. I could have probably adjusted the view to loop through this data directly or maybe even changed the JavaScript but as you can see, I didn't.

Now for the final steps, all you need to do is adjust your views to contain the handy dandy Carmen view helper methods and you're done.

#new.html.erb

<% javascript 'dynamic_states_for_user' %>
<% form_for @user, :url=> { :action => "create"} do |f| %>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<div><br/><%= check_box_tag("send_reg_email","true") %><%= label_tag('send_reg_email','Send welcome registration email to user?')%></div>
<div><br/><%= f.submit "Save" %> <%= submit_tag 'Cancel', {:confirm => 'Cancel changes?', :name => 'cancel'} %></div>
<% end %>

#_form.erb (my users record partial)

<tr>
    <td><%= human_label User, :country %>: </td>
    <td><%= country_select(:user, :country, nil, {:prompt => "Select a Country"})%></td>
</tr>
<tr id="state_field">
    <td><%= human_label User, :state %>: </td>
    <% if @user.country && Carmen::states?(@user.country) -%>
    <td><%= state_select(:user, :state, @user.country, {:prompt => "Select a State"}, { :style => "width: 230px;"}) -%></td>
    <% else -%>
    <td><%= select( :user, :state, options_for_select([],""), {:prompt => "Select a State"}, { :style => "width: 230px;"})-%></td>
    <% end -%>
</tr>
<tr>
    <td><%= human_label User, :zipcode %>: </td>
    <td><%= form.text_field :zipcode, :size => 15 %></td>
</tr>

That's all it takes to get the dynamic client side JavaScript implementation of Country and State paired select fields. Enjoy!

References

Railscasts – Episode #88

Jim Benton – Carmen on GitHub

Jim Benton – His blog with some other cool stuff.

SQL If you decided to go the DB route instead

Wednesday, December 2, 2009

Issue under Rails formatting date time values

I think Rails has a very nice way of handling the format of dates and times in the views. You can substitute your own formats when the default one used by rails doesn't meet your needs. There are numerous postings on how to do this and I've referenced a few at the bottom of this article. Read one of those articles if you need to find out how to do this. I'm going to cut right to the reason for this post. I had setup my own date format as such:

Time::DATE_FORMATS[:for_column] = "%b %d %Y (%I:%M %p)"

Then in my view I was using it like this:

<td style="text-align: center"><%= user.last_login_at.to_s(:for_column) -%></td>

Naturally I was doing this in several views and unfortunately some were working and some were not. I was on occasion getting the error:

"wrong number of arguments (1 for 0)"

on the call to user.last_login_at.to_s(:for_column)

Since I had a few working examples I spent quite a bit a time comparing the working examples with the failing ones. I found old posts on issues with concerning this topic and apparently there have been several issues with date time formatting under rails (no surprise here) and unfortunately a few of the posts sent me down the wrong path. After about an hour of wasted time I discovered the ticket #1701 on Lighthouse which shed some light on the subject. It turns out that the alias for to_s is not setup properly when the datetime field is nil. That means the to_s method of the nil object is being called and it doesn't have any arguments.

My work around for this situation was to create a helper method. Hopefully you find this post useful and it saves you the hour I lost.

    def fixDateTimeFormatting( field )

if(field)
field.to_s(:for_column)
else
field.to_s
end
end

References

NOTE: These are fairly old posts and contain information that is useful but not necessarily accurate for Rails 2.0+ so keep that in mind while reading.

practical ecommerce – Custom Date Output Using Rails

Ruby Forum – Changing default date format in Rails

APIDock – to_formatted_s

Saturday, November 21, 2009

Installing Autotest and Snarl on Windows

I was looking for a personal productivity boost (no cracks about having Windows please) and I decided to setup Autotest. Unfortunately for me the best information I could find to do this was slightly more than a year old. To have the same reference point I did you can see the post Andrew On Rails: Autotest and Snarl - Coding bliss is obtainable in Windows.

Before you try to setup Autotest I recommend confirming your current suite of tests are actually working even if they aren't all passing.

As a reference my important version numbers are:

Ruby 1.8.6, Gem 1.3.5, and Rails 2.3.4

I have Windows XP Professional Version 2002 SP3 and a laptop with Windows Vista Home Premium SP2 and I followed these steps to get Autotest setup and working with Snarl on Windows.

  1. Start with downloading and installing the latest version of Snarl. At this time that's Snarl R2.21 (V40.15) I picked the default installation path.
  2. Next I installed ZenTest (4.1.4) (don't forget the capital Z and capital T). I noticed that there is an all lower case zentest with lots of dependencies. I didn't use that one.

    gem install ZenTest

  3. I also installed autotest-rails which was recently split from ZenTest. (version 4.1.0)

    gem install autotest-rails

  4. Then install ruby-snarl. (said version 1.0.0 on the install but shows 0.0.8 on the folder under gems)

    gem install ruby-snarl

  5. Now download and install the GNU Diffutils package. I used the complete package dated May 24, 2004. Autotest uses this to figure out which tests have changed so it can just re-run those particular tests. You will need to put the bin directory into your system PATH.
  6. While you are adding that bin directory to your system PATH you also need to setup a "HOME" environment variable and point it to some place real. I used HOME = %USERPROFILE%
  7. The default icons used with ruby-snarl are located under the gems folder. On my box that is "C:\ruby\lib\ruby\gems\1.8\gems\ruby-snarl-0.0.8\icons". You are probably going to want a couple of nice images because these defaults are small. One for tests have passed and one for tests failing. You can find a couple here: http://www.danielfischer.com/2007/05/14/ruby-on-rails-bdd-with-autotest-growl-rspec at the very bottom of the page. Whatever images you come up with you need to drop them into that icon folder and use the same names as the defaults. There's probably a better way to configure this but hey, I was in a hurry, that's why I wanted Autotest setup this way.
  8. Now create a file named .autotest in your Rails application root directory. You can't use the GUI to create an extension only file name so you'll probably want to drop to a command prompt and just type Edit .autotest to get this going. The only line you need to include in this file right now is:

    require "autosnarl"

  9. At this point you should be able to drop to a command prompt in your Rails application root directory and run the command "autotest". NOTE: If you have an open command prompt you'll need to exit it and open another so that you get the PATH and the HOME environment variable changes you made. Running the autotest command should result in your tests running and the result being shown as a Snarl message.

References

ZenTest

Why Autotest?


Thursday, November 19, 2009

An apology

After many years I have finally decided to try some kind of regular routine to capture thoughts that might be useful to others. I was reminded to do this once again after slogging my way through a Ruby on Rails issue looking for information about how to configure something on Windows. I found some of the information I needed but not all and it took some piecing things together to arrive at a solution. Unfortunately, not documented well enough to post just yet but it will be coming shortly. All of this to was the lead in to say that I have used many blog postings, news groups, user forums and the like over the last 24 years of developing software. I am ashamed to say that I have contributed very little back into the collective during that time. I have helped many developers one on one (some of them will find this post amusing) over those years, however, those of you out there I don't know have seen a benefit for anything I've done. Here's my apology and hopefully the start of some real contributions.