Upcoming Events

It’s a great time to be a Rubyist in Austin. There are several upcoming events that I’m looking forward to attending.

First, I’m giving a talk on Rails Application Security at the Austin on Rails meeting tomorrow evening. The meeting will also feature lightning talks covering a variety of beginner topics. Be sure to get there early.

Next, the second session of my GeekAustin Beginning Rails class starts August 4. The last class went really well and I’m looking forward to teaching it again. There are still seats available. For full details and to sign up, see the EventBright page at http://geekaustinrailsclass.eventbrite.com/.

Then, the Lone Star Ruby Conf starts on August 11 with a day of training. Followed by the conference proper on August 12 and 13. The keynote speakers and session topics are all outstanding this year. I am not speaking (this year), but I plan to be an active participant. Hopefully I’ll see you around town.

Your First Rails 3 Plugin

On several different projects I have needed to find the newest and oldest record in certain models. The code to do this is pretty simple (especially in Rails 3).

For example, here is a snippet to find the newest Post:

@post = Post.order('created_at DESC').first

We can make this even better by defining a method in the Post class like this:

def newest
  order('created_at DESC').first
end

With this new method our code becomes:

@post = Post.newest

But now we’re faced with having to add that method to lots of different models. This sounds like a perfect job for a simple Rails 3 plugin.

It’s Just a Gem

Plugins in Rails 3 are created just like any other Ruby gem. You can use whatever you like to create a new gem. Currently, I’m using Bundler:

bundle gem date_filter

This will create several files for you. The most important are the gemspec file and the contents of the lib directory.

The gemspec

Your gemspec file tells the world about your gem. The first thing you’ll want to do is edit this file and fill in the information marked with TODO – your name, e-mail address, gem summary, and gem description.

The rest of the file should take care of itself. Note that the gem version is stored in date_filter/version.rb. Also, the list of files, test files, and executables is filled in automatically with git commands.

The lib directory

Inside the lib directory you’ll find a file called date_filter.rb and a directory called date_filter. A common practice is to keep the contents of date_filter.rb pretty minimal.

Most of your actual code should go in separate files inside the date_filter
directory. For example, here is my date_filter.rb file in its entirety:

require 'active_record'
require File.expand_path('../date_filter/base', __FILE__)

ActiveRecord::Base.class_eval { include DateFilter::Base }

Note that I am requiring ActiveRecord here. This is based on wycats advice – If You Override Something, Require It

Next I require base.rb inside the date_filter directory. This contains the source for the plugin.

The last line actually includes my code into ActiveRecord::Base. Since I am adding class methods, I use class_eval.

date_filter/base.rb

Finally, here is the code for the plugin. It’s common practice to separate class methods from instance methods in Rails plugins. In this case I have a separate module for the class methods.

When DateFilter::Base is included into ActiveRecord::Base the method included is called. This method then extends ActiveRecord::Base with the methods in the ClassMethods module.

module DateFilter
  module Base
    def self.included(base)
      base.send :extend, ClassMethods
    end

    module ClassMethods
      def newest
        order('created_at DESC').first
      end

      def oldest
        order('created_at ASC').first
      end
    end
  end
end

Building and Installing

If you made it this far, you’re ready to build and install your new plugin. Bundler includes some rake tasks to help with this
automatically. You can see these by running rake -T

rake build
rake install
rake release

rake build will create a directory called pkg and build your new gem into this directory. You can then install it with the gem command.

rake install will build and install your new gem. To use it in a Rails project, you will need to add it to your Gemfile and run bundle install.

Releasing

If you have an account at RubyGems.org you can also release your new gem. Check your profile page for your API key. Include your API key in ~/.gem/credentials as instructed, then run rake release to build and upload your gem to the site.

This should get you started building your own Rails 3 plugins. There are still a couple of pretty important things missing from this process – tests and documentation. I plan to cover both of these in a future post.

The complete source for this plugin is up at github. The gem is also available at RubyGems.org.

GeekAustin Rails Class

Starting on May 26 I will be teaching a beginning Ruby on Rails class for GeekAustin. The class will meet every Thursday from 7:00 PM – 9:00 PM at Cospace. I have developed a pretty ambitious course outline that I hope to cover in just 8 weeks.

The class is only $120 for 16 hours of training. The demand for Rails developers is so high right now, this is a tiny investment to get started in a very hot market. Someone who understands Rails inside and out can make that money back in a couple of hours (or less).

You will need to know some HTML and CSS. Previous programming experience would also be helpful, but is not required. Prior experience with Ruby or Rails is also not required. I’m going to cover everything you need to know and provide plenty of references to other materials to fill in any gaps in your knowledge.

I have really missed teaching, and I am so thankful for this opportunity. Developing the course outline and working on materials has been great. It seems like I’m exercising a part of my brain I haven’t used in a while. I honestly can’t wait to get started teaching this.

This class will fill up fast. For full details and to sign up, see the EventBright page at http://geekaustinrailsclass.eventbrite.com/

Editing Multiple Records in Rails

I recently had a requirement to create a single form with data from more than one record. This is a simple request, but I had never done it before in Rails.

After experimenting for a while (and reading quite a few forum posts and StackOverflow answers) I came up with a working solution. Hopefully this will save someone a little time in the future.

First, let’s create a simple Rails app for managing users. Each user will have a first name, last name, and e-mail address. I’m using scaffolding to generate the code.

rails new multi_edit
cd multi_edit
bundle install
rails g scaffold User first_name:string last_name:string email:string
rake db:migrate

Next, add the new routes for editing all users. I tried to stick to the RESTful convention with these. I’m just using the word ‘all’ in place of the :id.

match 'users/all/edit' => 'users#edit_all', :as => :edit_all, :via => :get
match 'users/all' => 'users#update_all', :as => :update_all, :via => :put

Now, let’s add the edit_all method to our UsersController to get started. The only thing it needs to do is get all users.

def edit_all
  @users = User.all
end

Next, we build the form for editing all users.

<%= form_for :user, :url => update_all_path, :html => { :method => :put } do %>
  <table>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>E-Mail</th>
    </tr>
    <% @users.each do |user| %>
      <%= fields_for "user[]", user do |user_fields| %>
    <tr>
      <td><%= user_fields.text_field :first_name %></td>
      <td><%= user_fields.text_field :last_name %></td>
      <td><%= user_fields.email_field :email %></td>
    </tr>
      <% end %>
    <% end %>
  </table>

  <div class="actions">
    <%= submit_tag %>
  </div>
<% end %>

The interesting part of this code starts around line 9. As expected, we iterate over the users with @users.each.

The next line tells Rails to name the fields for each user with array notation. For example, user_fields.text_field :first_name will output a text field named user[1][first_name].

The params hash will include a ‘user’ key that contains a hash of information for each user. The key for each of these hashes will be the user id.

Now that we know what the params will look like, it’s pretty straight-forward to write the update_all method.

def update_all
  params['user'].keys.each do |id|
    @user = User.find(id.to_i)
    @user.update_attributes(params['user'][id])
  end
  redirect_to(users_url)
end

We iterate over each key in params['user'], then find and update the user associated with that id. I am leaving error checking as an exercise for the reader…

The complete source code for this simple application is on my GitHub page at https://github.com/anthonylewis/multi_edit

A Better Looking Terminal

I spend a lot of time in the Mac OS X Terminal.app. Unfortunately, the built-in color schemes are all pretty terrible. I can’t stand to look at any of them for more than a few minutes.

So, one of the first changes I make on a new Mac is to update the default color scheme. It’s surprisingly easy to make something much easier on the eyes than the Basic theme. Here’s how I do it.

  • On the Terminal menu, click Preferences
  • Click Settings on the toolbar

  • Make sure the Basic theme is selected
  • Now click the Gear, then Duplicate Settings
  • Type the name Metal

  • On the Text tab, change the Text and Bold Text colors to Mercury and the Selection color to Steel

  • On the Window tab, change the Background Color to Lead

  • Finally, click the Default button

When you open a new terminal, you should see something that looks
more like this:

Now that is something I can work with for a while.

Rails on Rackspace Cloud – Part 2

Part one covered setting up a new Ubuntu server and getting Ruby 1.9.2 up and running with rvm.

Now we will finish the setup with a Firewall, MySQL, Apache2, and Phusion Passenger.

Setting Up the Firewall

Before we install the database and other services, lets get the firewall set up. On Ubuntu, I like to
use the Uncomplicated Firewall – UFW.

sudo apt-get install ufw

That will install the firewall. Now set the defaults, add some rules, and enable the firewall.

sudo ufw default deny
sudo ufw allow ssh
sudo ufw allow http
sudo ufw enable

To see the current rules, you can check the status.

sudo ufw status

Now the only ports open to the internet are SSH (22) and HTTP (80).

Installing MySQL

Now that we’re a little more protected from the outside world, lets install the database.

sudo apt-get install mysql-server mysql-client libmysqlclient-dev

And install the mysql2 gem.

gem install mysql2

Remember to ‘rvm use 1.9.2’ if you didn’t set it as the default.

Installing Apache and Passenger

The database is ready to go at this point, now we need a web server.

sudo apt-get install apache2 libcurl4-openssl-dev apache2-prefork-dev \
                     libapr1-dev libaprutil1-dev

That will install Apache2 and the extra development packages needed by Passenger. Now install the Passenger gem.

gem install passenger

Now we’re ready to install the Passenger Apache2 module. Note, this doesn’t actually install anything. It just builds the module and gives instructions for updating the configuration.

passenger-install-apache2-module

Now we need to create a new module load file to tell Apache about Passenger.

sudo vim /etc/apache2/mods-available/passenger.load

Here are the contents of passenger.load. The first two lines should be all on one line.

LoadModule passenger_module /home/testapp/.rvm/gems/ruby-1.9.2-p180/gems/
    passenger-3.0.5/ext/apache2/mod_passenger.so
PassengerRoot /home/testapp/.rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.5
PassengerRuby /home/testapp/.rvm/wrappers/ruby-1.9.2-p180/ruby

If we did everything right, we can enable the Passenger module now.

sudo a2enmod passenger

Now we need to set up our virtual host under sites-available.

sudo vim /etc/apache2/sites-available/testapp

Here are the contents of that file. You will obviously need to replace the xx.xx.xx.xx with the IP address of your server.

<VirtualHost *:80>
  ServerName xx.xx.xx.xx
  DocumentRoot /home/testapp/testapp/public
  <Directory /home/testapp/testapp/public>
    AllowOverride all
    Options -MultiViews
  </Directory>
</VirtualHost>

Disable the default web site and enable our new test application.

sudo a2dissite default
sudo a2ensite testapp

Setup a simple Rails App

Create a simple Rails application in your home directory just to make sure everything is working.

rails new ~/testapp
cd ~/testapp
bundle install
rake db:migrate RAILS_ENV=production

Finally, reload the Apache2 configuration.

sudo /etc/init.d/apache2 reload

Go to your server’s IP address in your browser and you should see the default Ruby on Rails index page.

Rails on Rackspace Cloud – Part 1

This is my recipe for starting up a new Rackspace Cloud Server and getting it set up for hosting Ruby on Rails applications.

Part one will take you from a new server to a working installation of RVM and Ruby. Part two will cover installing MySQL, Apache and Phusion Passenger.

If you don’t already have an account with Rackspace, I encourage you to go over to
http://www.rackspace.com/cloud/ and check them out.

I prefer Ubuntu Linux, so let’s start with that.

Starting a New Server

First, sign in to your Cloud Control Panel, then click Hosting, Cloud Servers.

Click the Add Server button, scroll down to Ubuntu 10.10 (Maverick Meerkat), then click the Select button.

Now type in a server name and select how much RAM you’ll need, then click the Create Server button.

After a short wait, your new server should be ready to go. You will receive an e-mail with your new server’s IP address and root password.

Connect to the IP Address with SSH, log in as root with the password provided, and lets get started.

Initial Login

The first thing you should do at this point is change the root password.

passwd

Type in your new root password twice. Now let’s add a new user account.

adduser testapp

Type in the information for your new user. Add the new user to the sudo group so you can execute commands as root.

adduser testapp sudo

Now that we have a new account to use, we need to deny the root user access via ssh. This will stop people trying to brute-force our root password.

vim /etc/ssh/sshd_config

Find the line that contains “PermitRootLogin” and change the value from “yes” to “no”. Restart the ssh server when you’re done.

/etc/init.d/ssh restart

We have set up a new user account with sudo access and denied root login via ssh, so let’s log out for now.

logout

New User Login

Now reconnect with your new user account and let’s make sure all of our software is up to date.

sudo apt-get update
sudo apt-get upgrade

This should be really fast. Rackspace’s internet connection puts mine to shame.

Installing RVM

Next, we’ll install git so we can install rvm.

sudo apt-get install git-core

Now copy and paste the command below to install rvm:

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Once this finishes, you will see a lot of instructions for setting up rvm as well as a nice “Thank you” from Wayne.

rvm automatically creates a file called .bash_profile in our home directory. This causes bash to skip loading
the regular .profile.

The only thing in .bash_profile is rvm configuration, so let’s just delete it…

rm .bash_profile

and add the configuration to .profile instead.

vim ~/.profile

Add this line at the very bottom:

[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"

Finally “source” your .profile file so the change will take effect.

source ~/.profile

Installing Dependencies

Now we’ll install the rest of the packages we need to build ruby. RVM can provide us a list of needed software.

rvm notes

Look at the line starting with “For Ruby” to get a list of dependencies.

sudo apt-get install build-essential bison openssl libreadline6 \
                     libreadline6-dev curl git-core zlib1g zlib1g-dev \
                     libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev \
                     sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
                     ncurses-dev

Again, this shouldn’t take long.

Installing Ruby

We’re finally ready to install Ruby.

rvm install 1.9.2

We have Ruby 1.9.2 now, let’s use it.

rvm --default use 1.9.2

Installing Rails

Now that we have Ruby set up, we’re ready to install Rails. It should be as simple as this:

gem install rails

Note that when you’re using RVM, you do not have to precede this with “sudo”.

After another short wait, you should be all set.

Verify that the ruby and rails commands work as expected. In part 2 we’ll setup MySQL, Apache and Passenger.

Happy Pi Day

In honor of Pi Day, I thought I would write a little Ruby script to generate pi to a few decimal places.

A quick trip to the Wikipedia page for pi turned up many formulas for computing pi. I took one of the easy ones and set about writing some code.

Most of the formulas involve the factorial function. Unfortunately, Ruby doesn’t have a built in method for computing the factorial. After a little Googling, I found a nice, functional example at the Rosetta Code wiki.

Putting that all together, I ended up with this:

def fact(n)
  (1..n).reduce(1, :*)
end

sum = 0.0

(0..8).each do |n|
  a = fact(2 * n) ** 3.0
  b = 42.0 * n + 5.0
  c = fact(n) ** 6.0
  d = 16.0 ** (3.0 * n + 1.0)

  sum += (a * b) / (c * d)

  puts 1.0 / sum
end

Note that I’m only iterating 8 times. On my PC, that gives pi out to 15 decimal places which is all of the precision available in a floating point number.

Exploring ODBC with Ruby DBI

I recently found myself in an interesting situation.
I needed to extract data from a database. Unfortunately,
all I had to work with was an ODBC name.

If this were a MySQL database, I would have used the
command-line interface to check out the structure and
see what was available.

In this case, I didn’t have a command-line interface.
What I did have was Ruby and irb. Here’s how I got the
job done.

Required Gems

Three gems are required to make this work. First, we
need dbi and a driver (or dbd). The dbd-odbc driver also
requires the ruby-odbc gem.

dbi
dbd-odbc
ruby-odbc

In order to install ruby-odbc on Windows, you will need to
compile it from source. I used the excellent
DevKit
provided with the RubyInstaller and
had no problems.

Connect

Let’s assume that the ODBC Data Source Name is “TestData”.
First, we require the DBI library, then connect to the data
source.

require 'DBI'

dbh = DBI.connect("DBI:ODBC:TestData")

You can also pass a username and password after the connection
string if required.

List and Describe Tables

Now that we have a connection, let’s see what tables are
available.

dbh.tables

My test database only has one table. It’s called “Table1”.
Let’s list the columns in this table.

dbh.columns "Table1"

This will tell us the type of data stored in each field in
addition to the name.

Query For Data

In order to see the actual data, we can prepare and execute
an SQL query. In this case, the separate prepare and execute
is not really necessary, but it’s a good habit to get into.

sth = dbh.prepare("SELECT * FROM Table1")
sth.execute

row = sth.fetch

The fetch method will return a row of data at a time until
there is not more data. At that point it returns nil. Calling
fetch again after it returns nil will result in an exception.

A Complete Example

Here’s a simple example of connecting to the ODBC database and
displaying all of the data in a tab separated format.

require 'DBI'

dbh = DBI.connect("DBI:ODBC:TestData")

sth = dbh.prepare("SELECT * FROM Table1")
sth.execute

puts sth.column_names.join("\t")

while row = sth.fetch
  puts row.join("\t")
end

sth.finish
dbh.disconnect

You could also require the CSV class and use it to generate comma-separated
output.

To Hex and Back (With Ruby)

I am a big fan of plain text. It is easy to view and easy to edit. Unfortunately, it is sometimes necessary to work with binary files and data.

Ruby’s inspect method does a decent job of showing the contents of a binary string, but sometimes I need something a little more powerful.

Back in the day I would use a hex editor to open binary files and decipher their contents. I don’t have a need for a hex editor anymore, but I would like to occasionally view binary data in the same format.

After some intense Googling and Ruby doc reading, I came up with a few methods to convert a binary string to hex, and convert a string of hex back to the original binary.

Bin to Hex

To convert a string to it hex representation, first take each byte, convert it to hex, then join all of the hex digits back together.

def bin_to_hex(s)
  s.each_byte.map { |b| b.to_s(16) }.join
end

If you like spaces between the hex digits, change join to join(‘ ‘)

Hex to Bin

Converting the string of hex digits back to binary is just as easy. Take the hex digits two at a time (since each byte can range from 00 to FF), convert the digits to a character, and join them back together.

def hex_to_bin(s)
 s.scan(/../).map { |x| x.hex.chr }.join
end

If you find yourself using these frequently in a project, you could add the methods to the String class.

TIMTOWTDI

Of course, there is more than one way to do this. Ruby also provides the handy pack and unpack methods for Arrays and Strings respectively. These are a little more cryptic since you need to know the meaning of the format string to understand what’s going on.

def bin_to_hex(s)
  s.unpack('H*').first
end

def hex_to_bin(s)
  s.scan(/../).map { |x| x.hex }.pack('c*')
end

Check the Ruby documentation for Array and String for a complete explanation of pack and unpack.

Examples

Here’s the output of a quick IRB session to demonstrate how this works.

irb(main):001:0> s = "Hello, World!"
=> "Hello, World!"

irb(main):002:0> s = s.each_byte.map { |b| b.to\_s(16) }.join
=> "48656c6c6f2c20576f726c6421"

irb(main):003:0> s = s.scan(/../).map { |x| x.hex.chr }.join
=> "Hello, World!"

These methods are no replacement for a hex editor, but if you need to check an encryption key or some other short string of binary, they can be just the thing.