eddorre

Found 22 posts tagged with 'ruby'

Installing Ruby on Rails, PostgreSQL, MySQL on Snow Leopard

Tuesday October 27, 2009 19:52 | comment icon 11 Comments

Snow Leopard, Apple’s latest release of their OS X Operating System, was released last month. I pre-ordered it from Amazon but it’s only now that I’ve gotten around to installing it on my machines. I first installed it on my Mac Mini as a fresh install and because of that, I wanted to document the process. I probably could have upgraded Leopard to Snow Leopard, but I didn’t want 32bit binaries floating around where I could have been using a 64bit binary.


Determining whether or not your Mac is 64bit or 32bit is based on the processor. Click on the Apple logo in the menu bar and choose About This Mac. Look at the processor type. If it’s a Core Duo, you have a 32bit Mac, if it’s a Core 2 Duo then you have a 64bit Mac. Keep that in mind when installing applications like RubyGems and database drivers.

One more thing, with this guide, I stuck with MacPorts for some application installs. I know that Homebrew is all the rage nowadays, but I’ve had little to no trouble using MacPorts, so that’s what I’ve stuck with.

Installing XCode

This whole process breaks down if you don’t install XCode, so go ahead an do that now. You could probably download it online but since the Snow Leopard DVD is only a month old (at the time of this writing), go ahead an install it from there.

Just in case you’ve never installed XCode, it’s located on the DVD in the Optional Installs directory. Just run the Xcode.mpkg installer. Choose the default settings for the installation.

Installing MacPorts

Head on over to the MacPorts site and download the dmg disk image for Snow Leopard. Once the download is complete, run the installer from the mounted disk image. I chose the defaults through the installation process.

The Snow Leopard version of MacPorts should modify your $PATH automatically so that you can run “port” commands from the Terminal without having to prefix it with the location path of the MacPort binaries. If you want to make sure, you can run this command from the Terminal:

cat ~/.profile

You should see something similar to this:

# MacPorts Installer addition on 2009-10-08_at_19:43:18: adding an appropriate PATH variable for use with MacPorts.
export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:$PATH
# Finished adapting your PATH environment variable for use with MacPorts.

If you don’t see this, you’ll want to edit your path to include /opt/local/bin and opt/local/sbin. You can do this by opening your .profile file with TextEdit and make the changes:

sudo '/Applications/TextEdit.app/Contents/MacOS/TextEdit' ~/.profile

Add the following lines before “$PATH”:

/opt/local/bin:/opt/local/sbin:/usr/local/bin:

Now you should be able to run the command

which port
and see the output
/opt/local/bin/port

MacPorts should correctly compile the correct version (32bit vs 64bit) of applications and libraries for you based on your CPU (confused about which Mac version you have?). If you’re feeling paranoid and want to force it to always use a certain mode, you can use your favorite text editor and edit the file at:

/opt/local/etc/macports/macports.conf
Example:
open -e /opt/local/etc/macports/macports.conf

Look in the file for the commented out “build_arch” declaration. If you want to force 64bit mode for example, you’d uncomment the line and change the value to x86_64.

Ruby, Rails, and Gems

Snow Leopard, like it’s predecessor comes bundled with a version of Ruby, Rails, and RubyGems. Since I’ve been using Rails professionally, I always like to install my own version of Ruby and RubyGems from MacPorts. I also like to download Rails from the gem source myself.

Before we can do that, we should hide the versions that come pre-bundled with Snow Leopard.

You can do that by running the following commands in the Terminal (inputting your password where requested):

sudo mv /usr/bin/ruby /usr/bin/ruby.orig
sudo mv /usr/bin/gem /usr/bin/gem.orig
sudo mv /usr/bin/rails /usr/bin/rails.orig

Finally we’re ready to install Ruby and RubyGems via MacPorts. Just run the following from the Terminal:

sudo port install ruby rb-rubygems

This will take a while, so you might want to take a break and stretch your legs while it’s doing its business. Once Ruby and RubyGems have been installed, you can go ahead and install Rails itself.

sudo gem install rails

Installing Your Database Servers

I use both PostgreSQL and MySQL but you don’t have to install them. In fact, since Rails uses SQLite for development (by default) you might not need to install either of them. With that being said, I highly recommend to install both database servers just in case you need to use them.

Installing both is quite trivial but make sure to pay attention to the output at the end of the commands as it has text that you’ll want to copy and paste into your Terminal. Run the following commands for PostgreSQL:

sudo port install postgresql84 postgresql84-server

Again, make sure you read the post install text as it’ll direct you to install a default database, create a default postgres user, and setup PostgreSQL to start automatically at start up. (recommended).

Once you’ve run the commands that it has suggestion, it’s a good time to add PostgreSQL to your path so that you can install the database driver. Again, open your .profile and edit your path and add the following right before “$PATH”.

/opt/local/lib/postgresql84/bin/:

Install the PostgreSQL Rails database driver by running the command:

sudo env ARCHFLAGS="-arch x86_64" gem install pg

If you want to install the 32bit driver, then you can just run:

sudo gem install pg

Installing MySQL is as simple as installing PostgreSQL. In the Terminal:

sudo port install mysql5 mysql5-server

Just like in the PostgreSQL install, make sure you read the post install text. It’ll have you setup a default database, and will give you a command so that MySQL can load at start up (recommended).

After MySQL has been installed you’ll want to install the MySQL database driver for Rails:

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

If you want the 32 version:

sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config

By default, MySQL likes to use UNIX sockets for communication and therefore it needs a .sock file. I usually like to store mine in /tmp/mysql.sock. It doesn’t exist by default, so you’ll have to create it:

sudo touch /tmp/mysql.sock

After that file has been created you’ll have to tell MySQL to use your newly created socket file:

sudo touch /opt/local/etc/mysql5/my.cnf
sudo '/Applications/TextEdit.app/Contents/MacOS/TextEdit' /opt/local/etc/mysql5/my.cnf

Add the following to the my.cnf file:

[mysqld_safe]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock

PostgreSQL and MySQL should now be installed but you’ll want to install the SQLite database driver gem. It’s dead simple:

sudo gem install sqlite3-ruby

Installing Your Web Server

I use Passenger for my development web server and I highly recommend you doing the same. It’s not necessary, so you can certainly skip the step if you’d like.

Before we start installing anything, let’s turn on Apache. Go to the Sharing Preference pane under System Preferences and check Web Sharing. This should activate Apache.

Let’s install the Passenger gem and the Apache 2 module:

sudo gem install passenger
sudo passenger-install-apache2-module

Make sure that you read the text after the Apache module has been installed. It will give you lines of text that you’ll need to copy into your Apache config file.

Here is a sample of mine:

# Passenger modules and configuration
LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6
PassengerRuby /opt/local/bin/ruby

I create a Passenger specific config file to hold this information:

sudo touch /etc/apache2/other/passenger.conf

Open the newly created file in TextEdit (you know the drill here sudo ‘/Applications/TextEdit.app/Contents/MacOS/TextEdit’ /etc/apache2/other/passenger.conf) and copy the lines from the post Apache 2 module install as well as some additional text. Here is a sample from my passenger.conf file:

# Passenger modules and configuration
LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6
PassengerRuby /opt/local/bin/ruby

# Set the default environment to development
RailsEnv development

# Which directory do you want Apache to be able to look into for projects?
<Directory "/Users/carlos/work">
    Order allow,deny
    Allow from all
</Directory>

You’ll obviously want to replace the path “/Users/carlos/work” with your own. This path doesn’t have to be specific as we’ll be using the Passenger Preference Pane to tell it where are projects are at.

Since the Passenger Preference Pane relies on Ruby Cocoa, we’ll need to install before we start to configure it.

NOTE: The Passenger Preference Pane is 32bit only so you’ll get a warning that the System Preferences has to relaunch in 32bit mode when you try to run it. It doesn’t negatively affect anything but it’s still a minor annoyance. Once "MacRuby"http://www.macruby.org/ is stable enough it’ll be ported there and the warnings will go away.

Installing Ruby Cocoa is a simple port install:

sudo port install rb-cocoa

You might get errors setting up your projects using the Passenger Preference Pane because it expects to find the Snow Leopard bundled version of Ruby. Since we installed our own, I just trick it by running the command:

sudo ln -s /opt/local/bin/ruby /usr/bin/ruby

Next, download and install the latest Passenger Preference Pane (as of this writing it’s version 1.3). Adding projects to your Passenger Preference pane should be simple as it’s all GUI driven. When choosing a project path, just point it to the root directory of the project and it’ll figure out the rest.

Even though I prefer Passenger for development mode, it’s still handy to install Mongrel (and simple too).

sudo gem install mongrel

Parting Thoughts

At this point, you should have a working development environment for Ruby on Rails. I’ve tried to distill my notes into something readable just in case someone comes across this. If you have any problems with the steps above, feel free to ask a question in the comments.

Canonical URLs

Tuesday April 14, 2009 02:09 | comment icon 2 Comments

Canonical URLs are all the rage on the Internet nowadays. All one has to do is do a Twitter search for canonical to see the conversations going on.

The problem is this, micro-blogging services such as Twitter only allow a certain number of characters, so a URL like this http://eddorre.com/posts/buildin-the-blog-part-5-refactoring-part-2, is too long. This is where URL shorteners like tinyurl.com come in.

They take a long, but perfectly fine URL, and make it something like this: http://tinyurl.com/Hukjfd (this is an example – not a real link). This is much more useful on Twitter where character space is at a premium. However this has its own problems, one is trust. How can you trust tinyurl.com to actually be delivering you to a URL that you would even want to visit? Short answer, you don’t. Also, what happens if tinyurl.com goes away one day? Any search on Twitter that uses these links immediately becomes less valuable. It’s the opinion of some on the Internet, that a site should take care of its own short urls.

For example, the link http://eddorre.com/posts/buildin-the-blog-part-5-refactoring-part-2, could become http://eddorre.com/s/SQ2BAs. Notice that the domain remains the same and short url is under my control. If the link goes away it’s MY fault not someone else’s. I have a vested interest in making sure that the link doesn’t go away. It doesn’t solve the trust issue, but at least you know that it’s a link coming from eddorre.com instead of anywhere on the Internet.

Enter the debate about canonical URLs and rev=canonical. The theory behind rev=canonical is simple. When I include a link like this: http://eddorre.com/posts/buildin-the-blog-part-5-refactoring-part-2 in Twitter or a similar website, they will then load up the original link and look inside the HTML for markup that looks like this:


<link rev="canonical" href="http://eddorre.com/s/SQ2BAs" />

When Twitter or a similar service finds this tag, they should then replace the long link with the short one. It makes sense but this does have one drawback that will most likely kill its adoption. It’s expensive. Twitter, for every link that is posted, has to connect to the URL, parse the HTML and then return a new link if it supports canonical URLs.

With that in mind, there is a proposed new HTTP header for canonical URLs that a web server could return to a service like Twitter. Something like “X-Rev-Canonical: href=”http://eddorre.com/s/SQ2BAs". This way, Twitter or other services just have to do a GET request to the original URL and it would just return them the short URL. No downloading and parsing the HTML. Whether either of these methods becomes widely adopted remains to be seen.

This past Saturday, after reading comments in Twitter and blogs about short urls, I decided to try coding up my own system for my blog. Turns out it only took me about 15 minutes to code something in Ruby/Rails.

Here is how I did it.

  • I created a migration to my posts table to include a short_url column
  • Created a before_create callback method in my post model to create a short_url.
  • The creation of the short_url is done by randomly mixing 6 characters from the characters available in Base 62 encoding (meaning: 0-9, A-Z and a-z).
  • To create short_urls for all of my older blog posts, I just created a migration that looped through all of the blog posts and generated this random token string for all of those and saved them.

I create a named route similar to the following:


map.short_url "/s/:short_url", :controller => 'posts', :action => 'show'                                   

Next, in my controller I did something similar to this:


    if params[:short_url]
      @post = Post.find_by_short_url(params[:short_url])
      redirect_to post_path(@post), :status => :moved_permanently and return
    else
      @post = Post.find_by_permalink(params[:id])
    end

There you have it. Something quick and dirty in about 15 minutes. Now if I want to post links to my blog on Twitter, I can use my own short url instead of using a service like tinyurl.

I should note that this probably isn’t the best way of doing things and it’s most certainly not the only way, but for a quick hack project on a Saturday afternoon, it fit the bill.

I forgot to mention that the inspiration for this post was Duncan Davidson’s post Everybody Wants Short Links.

Buildin' the Blog: Part 5 - Refactoring: Part 2

Saturday March 14, 2009 16:26 | comment icon 1 Comment

In my last Buildin’ the Blog article, I wrote about how I cleaned up my comments controller by moving all of the processing to the model. In this follow-up article, I’m going to write about how to access properties that aren’t part of your model object (aka table).

Take for example, a simple comments database table. It might look like this:

id full_name email_address url body

As you can see this is pretty straightforward, a single comment is comprised of a full_name, email_address, and the body. These attributes can easily be checked and processed in our comment model. Here comes the tricky part.

Take for instance my comment form below:

comment form photo

Name, email address, URL, and the body of the comment can all be mapped to database table fields. Unfortunately, Remember Me and Subscribe Via Email cannot and should not.

A beginner in Rails might write something like the following in their controller code:


if params[:subscribe]
#create a subscription record here
end

This code works but it leaves a lot of logic in the controller. The controller should be fairly lightweight, “I accept input from the user pass it to the model and then I pass it back to the browser/user.”

In order to get non-database bound fields to the model we use Ruby’s attr_accessor declaration (we could use attr_writer too to only write attributes and not read them).

For example:


class Comment < ActiveRecord::Base
  attr_accessor :subscribe
end

This allows me to create a form like the following:


  <% form_for @comment do |f| %>
  <%= f.text_field :full_name %>
  ...snip...
 <%= f.check_box :subscribe %>
 <%= f.submit %>

Once this is done, I can check what the value of the checkbox was set to in the model in a callback (let’s say either a before_save or an after_save):


  def before_save
    if self.subscribe == 1
      #create a subscription record here
    end
  end

It’s that simple. Now all of my logic can be done in the model.

With that out of the way, here is something to watch out for. Let’s say that you have a comments table that looks like this:

id full_name email_address url body is_admin

Obviously, the is_admin attribute should be set by the application and not by the user but unless you protect your model, the user can set any attribute he wants. Let’s say that you have a simple comments form with full_name, email_address, url, and body. The is_admin attribute is not displayed as a form field.

A malicious user could come by and change the form by adding the following or by submitting to the comment form using cURL. Here is an example:


  <input type="checkbox" name="comment[is_admin] checked="checked" />

By crafting this form and sending it, the user automatically becomes an admin!

One way to protect your application from this type of malicious activity is by protecting fields that should never be set by the user behind the attr_protected declaration. For example:


class Comment < ActiveRecord::Base
  attr_protected :is_admin
end

This will stop malicious users from trying to set attributes that should never be set by the user.

Buildin' the Blog: Part 5 - Refactoring

Sunday February 15, 2009 21:58 | comment icon 0 Comments

It’s been a long time since I posted something in this series, almost 3 years to be exact, and it’s about due.

One of the things that developers do when they are new to the MVC paradigm/Rails is to litter their controllers with all sorts of business rules code. This isn’t a fault really. For beginners it’s a way to get your app and running quickly.

As a developer matures with the MVC paradigm, they begin to see that there is a better way to do things (think Fat Model/Skinny Controller). That certainly was the case with me.

For instance, the create action of my blog’s comment controller (the heaviest action by far) weighed in at a hefty 61 lines of code. After doing a bit of refactoring, my controller has dropped to 25 lines of code. Still not perfect, but all of the comment processing code has been moved into the model.

Let’s take a look at how and why I made the changes.

First thing is first. Since I’m using the Akismet web service to check for comment spam, I need to track the referrer, the IP address of the client, and the User Agent.

I used to have a line of code in the create action that got this information by calling a method in the Application Controller.


options = get_browser_info

That method was defined as:


def get_browser_info
  options = { :ip_address => request.env["REMOTE_ADDR"], 
                :user_agent => request.env["HTTP_USER_AGENT"], :referer => request.env["HTTP_REFERER"] }
end

This worked, but it lacked a little sophistication.

The new method in the Application Controller:


def fetch_browser_info
 @browser_info = { :ip_address => request.env["REMOTE_ADDR"], 
  :user_agent => request.env["HTTP_USER_AGENT"], :referer => request.env["HTTP_REFERER"] }
end

Now in the Comments controller, I can run a before filter on the actions that need this:


before_filter :fetch_browser_info, :only => :create

Unfortunately, the old Akismet plugin that I was using, ror_akismet, enforced the use of extra methods in the controller. I changed this up, by copying the akismet.rb file to my lib directory and removing its dependence on the controller. And yes, I know that ror_akismet is the old library file and rakismet is the replacement. At the time, I didn’t want to install and futz with the new plugin.

That allowed me to pull this entire code block:


if is_spam?(:comment_content => @comment.body, :comment_author => @comment.name, 
                :comment_author_email => @comment.email, :user_ip => @comment.ip_address, 
                :referrer => @comment.referer, :user_agent => @comment.user_agent)

That now goes into the model. With a code block that looks like this:


if is_spam?( { :comment_content => self.body, :comment_author => self.name, :comment_author_email => self.email, :user_ip => self.ip_address, :referrer => self.referer, :user_agent => self.user_agent }.merge(self.akismet_attributes))

That’s it for this edition of Buildin’ the Blog, but I’m not done rebuilding my Comments create action. In the next part of the series, I’ll cover how to access variables that aren’t part of your Model’s attributes (table columns) and a quick note about security.

Object#type Errors with Single Table Inheritance

Tuesday February 03, 2009 23:09 | comment icon 0 Comments

Everybody probably already know this but what the hell. I was working on some code recently using Single Table Inheritance and was getting errors in the console and log when comparing the type field.

Before I get into the error itself and what I’m doing to correct it, a little background on Single Table Inheritance. Suppose you have employees in your database and you have two employee types; managers and staff.

You might have the following model objects:


class Manager < ActiveRecord::Base
end

class Staff < ActiveRecord::Base
end

And in the database, you’d have two separate tables; one for managers and one for staff. This is fine if the Manager table and the Staff table differ greatly from one another, but if they are identical with the exception of the type (Manager or Staff) then they can be combined in one table and be referenced in Rails using Single Table Inheritance.

This is done by having one class that Manager and Staff inherit from:


class Employee < ActiveRecord::Base
end

class Manager < Employee
end

class Staff < Employee
end

Now you can have one table, Employee, with a type column that differentiates that two. For example:

id type full_name phone_number
1 Staff Joe Jukem 5035551212
2 Manager Joe Blow 7025551212

Now here is where the problem comes in. Apparently “type” shouldn’t be used in your code. So when you’re doing something like this:


x = Employee.find :first
if x.type == Manager
   do something here
end

You’ll get a message that reads: warning: Object#type is deprecated; use Object#class instead. Now, obviously, the fix is to use something like this:


x = Employee.find :first
if x.class == Manager
   do something here
end

That works, but I like the more readable version using the is_a? method. For example:


x = Employee.find :first
if x.is_a?(Manager)
   do something here
end

Manually Updating RubyGems

Sunday February 01, 2009 01:41 | comment icon 0 Comments

I just did a deployment of my blog and came across a nasty little problem. The deployment in question required that a database migration be run in order to create a new table. Unfortunately, when I tried to run the rake db:migrate command it complained that I was missing a gem. So I tried to install the gem using the command: sudo gem install [gem name].

Here is where the problem comes in. Since I was running RubyGems version 1.0.1, trying to install or update any gem (including updating itself!) would hammer my poor little web server. I think I waited at least 5-10 minutes before killing the process.

This happens because there is a bug in earlier versions of RubyGems. Updating to a newer version (at least 1.2.0) will take care of the issue. Unfortunately, since downloading the RubyGems update will kill the server using the gem update command, I had to install it manually.

First thing is first; download the gem manually using WGET (at the time of this writing the latest RubyGems is at 1.3.1.


wget http://rubyforge.org/frs/download.php/45904/rubygems-update-1.3.1.gem

Once it has been downloaded, install it:


sudo gem install rubygems-update-1.3.1.gem

Finally, update RubyGems:


sudo update_rubygems

If everything went OK, you should see 1.3.1 when running the command gem -v.

Once RubyGems was updated, downloading a single gem was almost instantaneous.

Blasting off on a Rocket Ship

Sunday December 07, 2008 23:16 | comment icon 2 Comments

It’s often said (and I wish that I could remember the exact quote) that in order to climb a mountain, you have to take 1000 individual steps. Over the past few years, I’ve been trying to climb over a mountain of my own; my attempted transition from working as a sysadmin to working with code as a web developer.

It’s been a long, arduous path with many days and nights sitting in front of my Mac trying to learn the ins and outs of a very fast moving target. There were times that I didn’t think that I would ever achieve my goals but there is a light at the end of every tunnel.

6 weeks ago, my hard work and determination finally paid off when I accepted a full time developer position at Planet Argon in the heart of Portland, Oregon.

I still can’t believe that I get to work on a Mac with my preferred web framework and programming language. Of course, these are just tools and even in the wrong environment the best tools won’t help you or make you happy. Luckily for me, the environment couldn’t be better. I work alongside a group of talented and funny individuals that make work seem…well not so much like work. I know, it’s cliche, but it’s true.

Extending XMPP and Ruby Part II

Sunday September 21, 2008 02:41 | comment icon 0 Comments

Last month I wrote the a post titled Extending XMPP and Ruby. The post dealt with incorporating a plugin system to be used with my XMPP script that I wrote about in the post XMPP and Ruby.

To summarize the goal of the XMPP Ruby script; it’s a lightweight XMPP (Jabber/Instant Message) agent that resides on servers. Using this agent, I can immediately tell if a server is up and running as well as pass it commands through my IM client and have it reply back to me with the output. To enforce security, the script had a set number of commands that it could execute.

This had the problem of not really being scalable or extensible. For example, in order to add allowed commands one would have to modify the actual XMPP script itself. Not good.

In order to rectify that, I authored the plugin system that dynamically loaded classes at start time. This made it possible for me to be able to instantiate any object from those classes and run the methods of those classes.

In the test script it worked fine, but when incorporated with the actual XMPP agent script it was still hobbled by the fact that if you wanted to instantiate a new object you’d have to modify the original script. Again, not scalable or extensible.

With this latest iteration, I have added the ability to dynamically instantiate objects based on plugins as well as the ability to call the methods of the object all from the IM interface.

figure1

Before we explore the code, let’s take a look at our file structure (pictured in Figure 1). Everything is contained in a top level directory titled xmpp_agent. There is an init.rb file which loads all of the plugins in the plugins directory which are: command.rb, iis.rb, network.rb, system.rb. Below the plugins, are the files test.rb and xmpp_agent.rb.

The test.rb file is a “scratchpad” file that I use to test functionality. It is not a unit test file. As the figure mentions, the command.rb plugin file is new to this iteration. This file is responsible for creating objects dynamically at runtime as well as dynamically executing methods from those objects.

Since running commands have been abstracted out to its own class, there is no need to have that resident in the xmpp_agent.rb file. That code has been removed from the previous incarnation (see XMPP and Ruby). Everything else remains the same in the xmpp_agent.rb file with the exception of a new require declaration at the top of the script; require ‘init’ – as this loads our plugins (see Extending XMPP and Ruby).

When you send the agent a message that is phrased like this (items in brackets are variables):

command: [plugin] [method name] [arguments]

It will create a new Command object and calls the run_command method.

The first thing that the run_command method does is it calls a command parser method shown below:


  def parse_command(command)
    #Strip the command part out of the string - we don't need it any more.
    command.slice!("command: ")
        
    #Create an array for the arguments
    arguments = command.split(" ")
    return arguments
  end

This removes the extraneous “command:” part of the IM message and returns the rest of the string to the run_command method which is defined below:


  def run_command(command)
    vars = self.parse_command(command)
    
    #Convert the first item in the array to a class
    begin
      class_name = Object.const_get(vars[0].capitalize)
    rescue Exception => e
      return "ERROR: " << e.message << ". Are you sure that the #{vars[0]} plugin is installed?"
    end
    
    #Remove the first item (class name) since it's not needed anymore
    vars.delete_at(0)
    
    #Get the method name and remove it from the array
    if vars[0]
      method_name = vars.delete_at(0)
    else
      return "ERROR: Are you missing the method name?"
    end
    
    #If there are more arguments left call remote method passing in args, else just call the remote method
    if vars[0]
      run_remote_method(class_name, method_name, vars.each {|x| "#{x}" })
    else
      run_remote_method(class_name, method_name)
    end
  end

Now that we have everything parsed like we need it, we call run_remote_method.


  def run_remote_method(class_name, method_name, *args)
    begin
      o = class_name.new
    rescue Exception => e
      return "ERROR: " << e.message << ". Can't create the object, is it in the plugin folder?"
    end
    
    begin
      o.send(method_name, *args)
    rescue Exception => e
      return "ERROR: " << e.message << ". Did you include this method in the plugin file?"
    end
  end

As you can see, we dynamically instantiate a new object based on the class name that we’re passing in. After the exception handling, we call the method of the new object followed by any arguments.

For example: Let’s say that I want my server to ping an address. Instead of logging into the server and running the ping command, I could use the IM client to tell the server to ping the address and give me the results. All I have to type into the IM chat window is the following: command: network ping -c2 eddorre.com. This will ping eddorre.com twice on *nix machines.

The script will dynamically instantiate a Network object (provided it’s in the plugins directory) and try to run the method ping followed by any arguments.

In order for this to work, the network plugin/class has to have a method for ping in it. Let’s take a look at the code for that:


  def ping(*args)
    command = 'ping ' << args.join(" ")
    #Execute the command and return the result
    `#{command}`
  end

From the code above, I have defined a method called ping which takes the arguments at the command line, appends them to “ping”, and then executes the command (the backtick symbols mean execute the command and return the result).

Now, I’ll admit, using IM as an interactive shell is sort of limiting, but it can be much more powerful. For example, let’s take a look at the IIS class. This class, would in theory, handle everything related to Microsoft’s IIS web server. Let’s say that we want to find out how many current anonymous users are on a specific web site on our web server. We can define a method to return that information via the IM interface.

For example, let’s say I call this from the IM interface: command: iis current_anon_users [website]

The code for the current_anon_users method is below:


require 'win32ole'

class Iis < Plugin
  def current_anon_users(site)
    wmi = WIN32OLE.connect("winmgmts:root\\cimv2:Win32_PerfRawData_W3SVC_WebService.Name='_#{site}'")
    wmi.CurrentAnonymousUsers
  end
end

The code is simple, use a WMI object to return the data using the built in performance monitor on the server.

Using this new extensibility, you would be able to send a message to an agent such as “record this show” or “turn on the lights” depending on what you wanted it to do. All you have to do is build the plugin for it.

Extending XMPP and Ruby

Tuesday August 26, 2008 03:38 | comment icon 3 Comments

After writing up my XMPP Agent written in Ruby, my friend Billy wrote a comment about a similar system written by Michael Still the author of Practical MythTV. His system for controlling MythTV over XMPP is the gtalkbot.

Curious as to how he worked around some issues, I downloaded the Python source code and stumbled my way through it. I was struck by the fact that he used a plugin architecture that would allow other authors to extend the functionality of his original program.

After seeing that, I decided that I would try something similar.

Without worrying about the XMPP Agent, I set out to code a plugin architecture. In a directory I have the following files:

  • init.rb (should probably be called plugin_loader.rb or something more descriptive)
  • test.rb
  • /plugins (this is a directory)
    • network.rb (inside the plugins directory)
    • system.rb (inside the plugins directory)

The code inside the test.rb file is simple enough:


require 'init'

puts “This is the allowed command set”

puts ALLOWED_COMMANDS

The first line of the code, loads the init.rb file which does the heavy lifting. The init.rb file has a plugin class defined. Other plugins will inherit from this class.

The plugin class is defined as:


require 'find'

class Plugin
  
  attr_reader :allowed_commands
  
  def initialize
    @allowed_commands = %w{ iisreset }
  end
  
  def load_plugins(dir, name="/^[a-z]+.rb/")
    plugins = []
    Find.find(dir) do |path|
        Find.prune if [".",".."].include? path
        plugins << path if File.basename(path).include? ".rb"
    end
    
    plugins.each do |item|
      puts "Loading plugin => #{item}"
      #Load the file
      require File.join(File.dirname(__FILE__), item)
      
      #Extract the file name from the directory name (without .rb extension)
      file_name = File.basename(item, ".rb")
      
      #Create a new object and instantiate it and find the allowed_methods attribute
      c = Object.const_get(file_name.capitalize).new
      puts "Loading command set for plugin #{file_name.capitalize} "
      puts c.allowed_commands
      
      #Add it to the array for allowed_commands
      @allowed_commands << c.allowed_commands
    end
  end
  
  def run_command(command)
    #Strip the command part out of the string - we don't need it anymore
    command.slice!("command: ")
    
    #Create an array for the arguments
    arguments = command.split(" ")
    arguments.delete_at(0) #Delete the first index, this is the command itself without arguments
    
    #Loop through the arguments and then delete them from the command string
    arguments.each { |item| command.slice!(item) }
        
    if @allowed_commands.include? command
      puts "#{command} is an allowed command"
      result = `#{command} #{arguments.join(" ")}` #Backticks are a shortcut for system(yourcommand).
    else
      result = "#{command} cannot be run"
    end
    return result
  end
end

At the end of the init.rb file is the code that actually starts loading the plugins:


app_plugins = Plugin.new app_plugins.load_plugins("./plugins") ALLOWED_COMMANDS = app_plugins.allowed_commands

Now it’s easy to extend the test.rb script by instantiating a new System object (one of our plugins) just by this simple code in the test.rb file:

tester = System.new

I can then call methods defined in the System.rb file (shown below):


tester.test

System.rb file:


class System < Plugin
  
  attr_reader :allowed_commands
  
  def initialize
    @allowed_commands = %w{ set shutdown }  
  end
  
  def test
    "This is a test"
  end
end

Now all of this was just really another proof of concept to find out if it could be done. I’m happy with the results even though I’m sure that there is a better way of doing it.

XMPP and Ruby

Friday July 11, 2008 23:28 | comment icon 2 Comments

Although I didn’t make it to Ezra’s RailsConf 2008 presentation on scaling Rails, I was highly interested in the topic and downloaded the slides immediately after they were available.

The big news from his presentation was the reveal of Vertebra which is billed as a Next Generation Cloud Computing/Automation Framework. One slide stood out and immediately got me thinking with the question XMPP is a realtime messaging protocol built fro IM/chat, great for communication between thousands of people, why not machines?

After a dealing with a couple of server failures at work where notification was less than satisfactory, I started mulling around the thought of using Ezra’s idea for a small scale XMPP agent that was used for server monitoring and command processing.

The result is just a small proof of concept that I put together for a recent lunch and learn demonstration. This simple XMPP agent logs into my XMPP server (I’m using Jive Software’s OpenFire) and sets its presence to available. It also immediately sends me a message saying that it’s reporting for duty.

I’ve implemented message handling in a FIFO manner with an array that acts like a queue. If you send the agent a message (using a standard XMPP client like Spark or Adium) it will reply with “Thank you for sending me the message {yourmessagehere}”. If you preface your message with command: then it will attempt to execute that command (provided that it’s in the allowed list of commands). The output of the command is then sent to the sender as an IM message.

Please remember that this is only a proof of concept and it’s not my intent to put this iteration into production.

So without further ado, the code.


require 'rubygems'
require 'xmpp4r'
include Jabber

class Agent
  
  def initialize
    user = JID.new('yourusernamehere/XMPPAgent')
    @password = 'yourpasswordhere'
    @client = Client.new(user)
  end

  def connect(server_name, port)
    #Connect to server sending username and password
    @client.connect(server_name, port)
    @client.auth(@password)
    
    post_connect if @client
  end
  
  def post_connect
    #Set default presence to available
    status = Presence.new.set_type(:available)
    @client.send(status)
    #Start a new queue array
    @queue = []
    register_callbacks
  end
  
  def disconnect
    @client.close
  end
  
  def register_callbacks
    @client.add_message_callback do |message|
      @queue << message unless message.body.nil?
    end
  end
  
  def send_message(recipient, text, reply=false)
    message = Message.new(recipient)
    message.type = :chat
      if reply
        message.body = "Thank you for sending me the message: " << text
      else
        message.body = text
      end
      @client.send(message)
  end

  def start_worker_thread
    worker_thread = Thread.new do
      puts "Started new worker thread"
      #Start a loop to listen for incoming messages
      loop do
        if !@queue.empty?
          @queue.each do |item|
            puts item
            #Remove the resource from the user, e.g., carlos@xmppserver/exodus = carlos@xmppserver
            sender = item.from.to_s.sub(/\/.+$/, '')
            
            #If the message included the line command: create a new command object and attempt to run it
            if item.body.include? "command: "
              send_message(sender, "I'll try to run " << item.body.to_s, false)
              input_command = Command.new
              command_result = input_command.run_command(item.body.to_s)
              send_message(sender, command_result, false)
            else
              send_message(sender, item.body.to_s, true)            
            end
            @queue.shift
            puts "Queue is now empty" if @queue.empty?
          end
        end
      end
      sleep 1
    end
    worker_thread.join
  end
end

class Command
  @@allowable_commands = %w{ ipconfig ifconfig iisreset ping dig }
  
  def run_command(command)
    #Strip the command part out of the string - we don't need it any more.
    command.slice!("command: ")
        
    #Create an array for the arguments
    arguments = command.split(" ")
    arguments.delete_at(0) # Delete the first index, this is the command itself without arguments
    arguments.each {|x| puts "Argument: #{x}"}
    
    #Loop through the arguments and delete them from the command string
    arguments.each {|x| command.slice!(x)}
    
    puts "This is the command after munging #{command.strip!}"
    
    if @@allowable_commands.include? command
      puts "#{command} is an allowed command"
      result = `#{command} #{arguments.join(" ")}` #Backticks are a shortcut for system("commandhere"). Join the arguments back in.
    else
      result = "#{command} cannot be run"
    end
    puts result
    return result
  end
end

bot = Agent.new
bot.connect("xmppserver", "5222")
bot.send_message("carlos@xmppserver", "Bot reporting for duty at #{Time.now}", false)
bot.start_worker_thread

Calorie Counter Application

Thursday April 03, 2008 00:30 | comment icon 7 Comments

Calorie Counter ApplicationDear GF and I have iPhones and she’s become increasingly addicted to the fact that she can access web applications online at any time (as long as she has at least EDGE access).

A couple of weeks ago, she was looking online for a calorie counting web application and she was frustrated by the fact that she couldn’t find something she liked. Since I have mad Google-Fu skills, she asked me to try to find something. Instead, I asked her what her requirements were and since they were simple enough, I offered to write an iPhone specific application for her in Ruby on Rails.

Even though the application is dead simple, I learned a lot this time around since I tried to follow the recommended practices defined by the Rails community from coding to deployment. I’ve still got some more to learn (does one ever stop learning? Maybe when you’re dead), but I’m becoming more and more confident in my Rails skills.

She’s been testing the application on my staging server for the last week and we’ve discovered some bugs that were pretty egregious. Now that I have those worked out, I’ve deployed the beta application at caloriecounter.eddorre.com.

Although the application was written specifically to be displayed on the iPhone, I’ve tested it using desktop browsers such as Firefox, Safari, and Internet Explorer 7 (IE 6 is dead to me – I won’t even test against it). With the exception of a CSS styling bug in IE 7, it’ll work just fine on your desktop.

In addition to to all of this, I’ve actually allowed open registration to the application so that anyone can use it. I’m actually quite nervous about this as no one has ever used my web software besides me. Apparently, it might get more use than I expected since Dear GF’s work is having some sort of Biggest Loser-esque challenge at work and several of her co-workers have expressed interest in using it.

One more thing, at this time, I’m hosting the application on my home server. If you decide to take it for a spin, please be patient with the poor box.

Removing Old Rails Session Files

Sunday September 23, 2007 18:29 | comment icon 0 Comments

I’m sure that this is elementary for all of the *nix experts out there but I recently discovered this and thought that I would share. Ruby on Rails, by default, holds session information on disk in [application root]/tmp/sessions/ and unfortunately they aren’t purged automatically. Even for small sites, the number if session files can quickly grow out of control. For large sites, it can bring an application server to its knees by filling up the disk.

The “best practice” for Rails sites is to use the database to keep track of sessions using following commands:

  • ruby script/generate session_migration
  • rake db:migrate

Then uncomment the line in the environment.rb file that reads: config.action_controller.session_store = :active_record_store

If you’ve completed the above steps, then your sessions should now be stored in the database but that doesn’t remove the session files from disk. If you’ve been running with sessions on disk for a while, the command, rm /[application root/tmp/sessions/ruby_sess.* will fail with the error “Argument list too long”. If this happens, you can delete the files by running the following command:

find /[application root]/tmp/sessions/ -name ‘ruby_sess.*’ | xargs rm

I found this little gem of information at ducea.com. The comments have other commands that you can run to delete mass files if necessary.

Akismet Ruby on Rails Plugin

Tuesday July 10, 2007 01:16 | comment icon 0 Comments

I’m re-doing my blog engine. I’m focusing on refactoring old crufty code as well as expanding my knowledge of Ruby on Rails.

So far everything is on track and I should be done with it soon. One of the things that I wanted to focus on was the use of modules and plugins. Last time, I was using my own code for accessing the Akismet web service. This time around, I downloaded the ror-akismet plugin and I’m extending my comments class using the built in downloaded methods.

However there seemed to be a bug in the works. Every time that I included the declaration “include Akismet” into my comments controller, all of the other methods would break.

I started tearing out bits of my code and then the modules’ code and no matter what I did, everything would go to hell when I added the include declaration.

It turns out that Rails (1.2.3) seemed to be freaking out because the plugin directory that was downloaded was called ror-akismet.

Once I changed it to ror_akismet, everything worked fine.

Ruby and Ruby on Rails Books

Wednesday September 06, 2006 20:37 | comment icon 0 Comments

The Unofficial Ruby on Rails blog has a list of 8 upcoming Ruby on Rails books. It’s a good list but unfortunately the list is incomplete.

I’ve compiled a list of all the Ruby and Ruby on Rails books that I know of. If there is a second edition of a version of the way, I’ll only list that in the upcoming section (with the exception of the book co-authored by DHH). There is no need to get books that are on their way out.

NOTE: None of the links below are Amazon affiliate links.

Ruby – Released

Ruby – Upcoming

Ruby on Rails – Released

Ruby on Rails – Upcoming

These are all of the ones that I know. If you think that I’ve missed some, let me know and I’ll add it to the list.

Rails' Growing Pains

Thursday August 31, 2006 03:07 | comment icon 0 Comments

Kevin Clark recently wrote an article titled Guide: Things You Shouldn’t Be Doing in Rails.  As the title suggests, the article outlines code that shouldn’t be used in Ruby on Rails applications.

The article was well intentioned and written a bit tongue-in-cheek but it sparked quite a debate in the comments. While I’m glad that Kevin pointed out some bad coding behavior, I think the article may have aroused such strong emotion because, for the most part, he didn’t list alternatives to the bad behavior.

For example; he advises that people should not to access instance variables that they didn’t create but he doesn’t give an example of how to fix this. This is going to light the fire under some people; especially people that are trying to learn this stuff for the first time.

An underlying theme in the comments has been the frustration with out of date and deprecated information all across the board. Even “The Book” (Agile Web Development with Rails: A Pragmatic Guide) will lead you astray with crufty code.

Obviously Rails is going through some growing pains and accurate documentation and tutorials are in heavy demand.

As a relative newcomer to Rails, I understand frustration with poor documentation quite well. If “The Book” is wrong, what’s the alternative?

Well, right now there aren’t many books available for Ruby on Rails. but I’ve managed to compile a list.

Here’s a list of published books and e-books that might help newcomers on their way.

If I missed one that you know of, let me know and I’ll be glad to throw it in the list.

More books are coming but the majority of them won’t hit the shelves until November or December of this year.

Update: Nuby on Rails, lists all of the deprecated code that shouldn’t be used in a new plugin. It’s good to know.

Ruby on Rails - From Start to Finish

Wednesday June 14, 2006 22:16 | comment icon 0 Comments

When I first started with the notion of doing Ruby on Rails, I had it in my head that I wanted to do it the “right” way. The “right” way, in my head, was to use it on the platform that it was written for; Linux.

I’ve always been a Windows guy, but I’ve never shied away from a challenge, so I took the bull by the horns and sat down to write a Ruby on Rails app. I got gored…and trampled…and mauled…and, well you get the idea.

Call me a sissy, but I was used to point and click installers. So, something that I thought would be easy wound up being significantly more difficult that I had expected.

I guess I underestimated it, after all, I had to learn everything from scratch; the operating system (although I’ve had some UNIX training in the past), the database, the web server, the programming language, and finally the web application framework.

I wanted to compile a set of notes for myself for when I have to do it again, so I wrote up some steps to get Ruby on Rails installed on Debian Sarge with a MySQL database, Lighttpd. This includes integration with the version control software, Subversion and walks through how to create a database and a simple lighttpd.conf file.

It should really detail the deployment application Capistrano, but I wanted to do the stuff hands on before learning a system with a level of abstraction. Maybe I’ll write up those notes when I get there.

The notes are just a simple text file and I’m always amenable to updating it in case I’m doing something horribly inefficient. Hopefully, they’ll save a newbie some time and anguish.

Buildin' the Blog: Part 2 - Installing Ruby on Rails

Tuesday January 31, 2006 01:43 | comment icon 6 Comments

Part 1 of this series is here.

I originally was going to have this part come later in this series, but I wanted to install Ruby on Rails a bit before I started writing my blog application so that I could become more familiar with the programming language and the web framework. Add to that, the fact that I installed it last night makes it fresh in my head.

I picked Kubuntu to be my development platform for a few reasons. I’d really like to use a Mac along with TextMate, but I don’t have the capital for a new Mac. Oh sweet, MacBook, I will have you one day…

But I digress, it’s probably best to use Kubuntu at first anyway. One of the reasons why I chose this distribution of Linux is because, well, I wanted to learn Linux. I chose this specific distribution because I plan on using Debian as my production platform and since Kubuntu is based on Debian it seemed to make sense. I should note that I don’t use Ubuntu because it comes with the terrible GUI, GNOME (although I’m perfectly aware that I can switch to KDE using Ubuntu, I just wanted it all in one package).

Anyway, it’s time to get to the good stuff.

With modern Linux distributions, you can install software using a package manager and Kubuntu (and Debian) is no different. I could have easily downloaded Ruby with the apt program and then installed Rails on top of it but the latest version avaliable to the apt program is Ruby 1.8.3 while the latest version of Ruby is 1.8.4. I should note that Ruby 1.8.3 is not recommended for use with Rails.

So I had two choices, install an old (and incompatible) version with apt or install from source.

I decided on installing from source. First thing is first, I gotta install Firefox in order to browse the web (I don’t really like Konqueror – the web browser that comes with KDE) and download the source.

I run this command to get Firefox:

sudo apt-get install firefox

This installs Firefox 1.0.7 and displays a warning message when loading, but that’s fine for now – it’s not critical. It’s time to get Ruby and then Rails. The Ruby on Rails site has very simplistic instructions on how to install both Ruby and Rails. They are deceptively simple and as I’ve found with all things Linux, it’s actually much harder than adverstised.

I created a directory in /home/carlos called work where I could download packages and compile the programs. I download both Ruby 1.8.4 and Ruby gems into these folders.

You have to install Ruby first, so I run this command in the directory where I’ve download Ruby:

tar xvf ruby-1.8.4.tar.gz

This creates a directory called ruby-1.8.4. Moving into that directory, I attempt to run this command:

./configure

And it gives and error stating that “no acceptable C compile was found in $PATH.”

I guess I have to install a C compiler so I run this command:

sudo apt-get install gcc

It does its thing and I try the ./configure command again. This time it’s another error. C compiler cannot create executables. Hrrm, it’s turning out that it’s not as easy as “download and go” after all.

After doing some Google searches, I found out that I need to install some development packages first, so I run the following commands (the second command is used for later when attempting to get RubyGems working):

sudo apt-get install libc6-dev
sudo apt-get install zlib1g-dev


BAM. That got it working. It does it’s thing and makes a make file. I go to make the…uh…make file and when typing in the command “make”, I get the error: bash: make: command not found. Unbelievable. I then run the following commands (which run without error):

sudo apt-get install make
make
sudo make install

I’m not sure why a base install of Kubuntu doesn’t have gcc, make, libc6-dev, and zlib1g-dev but I’ll leave that to smarter people to figure out.

I first have to unpack Ruby Gems. The command (to be run where I downloaded Ruby Gems) is

tar -xvf rubygems-0.8.11.tgz

That creates a rubygems-0.8.11 directory. The following commands are to be run in that directory:

sudo ruby setup.rb
gem install rails —include-dependencies

Note if you get an error here that reads: The error is no such file to load - zlib (LoadError), it means that you have to install zlib1g-dev first. Unfortunately you also have to go back and run the .configure, make, make install commands in the Ruby directory again.

In theory, Ruby and Rails should now be installed. Let’s test it out by running the commands:

rails /home/carlos/work/test
cd /home/carlos/work/test
ruby script/server

You should see WEBrick 1.3.1 startup and at this time, I’m satisfied that Ruby on Rails has successfully been installed.

All in all, it was way more complicated than it needed to be and if I wasn’t so determined to get it working I would have quit and just double-clicked the installer for Visual Studio.NET 2005.

Buildin' the Blog: Preface

Monday January 23, 2006 17:02 | comment icon 0 Comments

I’ve been working on updating this site to what I call “version 3” for a while. “Version 3” has been set to include a whole new look and design as well as some programming additions to make it…well, better.

At first I was committed to using ASP.NET as my programming platform of choice (this site currently runs under ASP.NET 1.1), but somewhere along the line, I lost enthusiasm for using it.

Along the way, I’ve discovered Ruby on Rails and I’ve become determined to use it for the new site. Unfortunately, using Ruby on Rails on the preferred platform (Linux or Mac OS X) makes the learning curve quite steep.

As I thought more and more about what I’ve learned and what I’ve still yet to learn, I decided to make a set of articles that went from the first step of building a blog to the final steps of deployment and rolling it out live.

It’s helpful for me to document my progress and it might be helpful for other people out there as well.

Some people might say that I’m re-inventing the wheel considering the amount of great blogging packages out there (Typo, Das Blog, .Text, Wordpress, Movable Type, etc). I don’t see it like that at all. Since my goal is to learn Ruby on Rails on an Open Source platform, I see as “figuring out how the wheel works; by itself and in conjunction with other systems.”

The technologies that I’m going to be using will help me build my skills by learning basic skills in Ruby on Rails like CRUD (Create, Retrieve, Update and Delete), as well as more advanced skills like XML-RPC and AJAX.

Hopefully, whoever reads these can pull something useful out of them.

Next up: Buildin’ the Blog: Part 1 – Design Web Standards and Design Inspiration.

Linux Books

Saturday December 10, 2005 19:21 | comment icon 3 Comments

Work is still continuing on migrating this site from ASP.NET to Ruby on Rails. The reasons why aren’t really the basis for this post, so I’ll exclude them from it.

The majority of Ruby on Rails sites run on Linux or a form of UNIX, so I figured that I would take the plunge and do so as well. I consider myself to be a pretty accomplished Windows administrator, but in the realm of Linux, I’m but a wee young lad.

With that in mind, I’m browsing Amazon.com to see if there are any books that might help to soothe the learning pains.

In addition to learning Linux (the right way), I’m also interested in learning Linux web servers the right way as well. Probably the most popular web server for Linux is the Apache server, but I know that LightTPD is starting to gain ground especially amongst Ruby on Rails developers.

Imagine my surprise when I couldn’t find any books on LightTPD. Now, I know that this is a fairly new web server, but I’m used to technical books being written on alpha and beta releases, so it was quite a surprise.

Too bad I don’t know more about it or I would write my own. I think it would sell like hotcakes (if written right).

Penny Arcade on RoR

Monday November 14, 2005 15:26 | comment icon 0 Comments

Penny Arcade has re-done their website. At first, I thought I hit the wrong site or something, but it’s growing on me. According to Gabe, the new version of Penny Arcade runs on Ruby on Rails.

Instead of me talking about it, it’s best just to quote his own words:

Penny Arcade right now represents one of the largest implementations of “rails” on the intertron. I went and looked at a website about rails and then I got a headache. From what I gathered its either some kind of cutting edge programming language, or a way to liquefy a mans brain inside his skull. I’m told that it means the site looks better and loads faster regardless of whatever hippy web browser you decide to use. Fuck M$!

Tutorials for Ruby on Rails

Tuesday October 25, 2005 22:52 | comment icon 0 Comments

After you’ve installed Ruby on Rails, you want to know what you’re doing. I strongly suggest that you purchase Programming Ruby: The Pragmatic Programmers’ Guide, Second Edition and Agile Web Development with Rails, but there are online tutorials that will get your started in case you don’t have those books.

View or read them in this order:

Finally, here are some good links that might help you on your new endeavor.

Follies Installing Linux and Ruby on Rails

Tuesday October 25, 2005 22:39 | comment icon 1 Comment

This past Saturday, I was determined to get Ruby on Rails
installed…in Linux. I could have gone the easy route and installed in
Windows, but I wanted…well I want to branch out from the standard
Windows world that I know.

It turned out to be a 12 hour exercise in frustration. All I can say
is, thank god for VMware. Without it, I would have lost my sanity.

I first started my little exercise with OpenSuse10. It’s a brand new
free version of Suse…and looking back with hindsight, I’ve come to
the conclusion that it might be too much on the bleeding edge.

Whenever I tried to compile Ruby, it would give me an error. Everytime
that I thought I was getting closer to the solution, it would blow up
in a different fashion. So I deleted the virtual disk (the virtual
equivalent of tearing your hard drive out of your machine and flinging
it off a 10 story balcony) so I tried one of the other Linux
distributions that I had downloaded; Kubuntu (the KDE version of
Ubuntu). I’ve used quite a few distributions of Linux over the years
(and have always come back to Windows), but this one has to be one of
the worst ever.

The install of Kubuntu was fairly easy. Too easy. Not only did it not
ask me for a root password, it didn’t ask me to create a user. I went
to create a directory on /var/tmp and naturally you have to use the
root account to do (sudo mkdir /var/tmp/carlos). When it asked for a
password I was flabbergasted. I didn’t give it one. I tried a null
password and the word password. When it didn’t take the second one, I
shut off the virtual machine and deleted the virtual disk. Time to
install another distribution. This time I tried Fedora Core 4.

I had to reinstall it twice because I’m such a newbie, but on the
second time I was able to download Ruby and Rails and succesfully
install them.

If I can recommend one thing for the Ruby and Ruby on Rails community,
it would be to make the install easier. If you think I’m out of my
mind, read this blog entry.
If that doesn’t make you frustrated with the install then nothing will.
His documentation is one of the reasons that I stuck through what I
did. I knew that there was a light at the end of the tunnel, even for a
Linux newbie like me.

I hope that your install goes better than mine, but here is what I did:

This is unrelated, but I thought that I would post it here. When you
install Suse10, Fedora Core 4, and any other OS into a virtual machine,
it’ll complain that the VMware tools are missing. Installing from the
RPM does nothing. You actually have to do this:


  1. On the VMware window itself, click on VM and select Install
    VMware tools. This should automatically mount the DVD to
    /media/<name of device>. In my case, it was in my DVD burner so
    the entire path was /media/dvdrecorder.

  2. I copy the tar.gz file to that temp directory (although I found
    out that the location of that temp directory might not be a good idea,
    but that’s a tale for another post). Using this command (at this point
    I’m su’d as root which is this command: su root) mv
    /home/carlos/Desktop /var/tmp/carlos/.

  3. Then I unpack the files using tar -xzf  /var/tmp/carlos/<name of file>

  4. And then finally I change into the newly unpacked directory cd
    /var/tmp/carlos/<name of new directory> and run a
    ./vmware-install.pl.

  5. Answer all of the questions and then choose my resolution.
    Unfortunately, to take effect, you’ll have to reboot and that command
    is, well, reboot. Finally I can see virtual machine at 1024*768.

Installing Ruby:
Note: During both installs, I had su’d to root. Command is su root.


  1. Download the latest verison of Ruby (at the time of this writing it’s 1.8.3).

  2. Move the tar.gz file to the tmp directory or your could unpack it
    there. The command that I used was mv /home/carlos/Desktop/<name of
    file> /var/tmp/carlos/.
  3. Unpack it: tar-xzf <name of file>.
  4. Change into the newly created directory: cd /var/tmp/carlos/<newly created directory>.
  5. Run this command: ./configure.
  6. Run this command: make.
  7. Run this command: make install.
  8. If the gods have smiled upon you, then Ruby has been installed.

Installing Rails:


  1. Download the latest version of Rubygems. At the time of this writing it’s 0.8.11.

  2. Move the .tgz file to the tmp directory. The command is: mv. /home/carlos/Desktop/<name of file> /var/tmp/carlos/.

  3. Unpack it: tar -xvf /var/tmp/carlos/<name of file>.

  4. Change into the newly created directory and run the command ruby
    setup.rb. NOTE: This is where it would fail to install on OpenSuse10. I
    could never get past that point with that OS.

  5. Run the command gem install rails —include-dependencies.

  6. If the gods have smiled upon you, then Rails has been installed.

Have a beer, you earned it.

end kanji