Rails 2.2, MySQL, and pain.

Posted by Brian in News, Rails (December 5th, 2008)

Rails 2.2 removes the MySQL native Ruby adapter from its codebase, instead requiring people who want to use MySQL with Rails to use the (better performing) MySQL gem. Unfortunately, Mac and Windows users seem to have some issues getting this installed.

Mac
My original article on this has been updated.

Windows
I’m working on an easy to use tutorial to solve this problem.

“Meet Rails” presentation materials from Chippewa Valley Code Camp

Posted by Brian in Rails, Howto, tips, web (November 24th, 2008)

I gave a talk at the Chippewa Valley Code Camp earlier this month where I built a Rails pastebin application using test-first development principles. Since there were no slides for this, I’ve prepared a small PDF that will walk you through the installation instructions and the coding of the application I built.

Download Meet Rails to get started.

You can grab the source code for the finished project at Github.

Watch this site, as this project may get turned into a full-scale book.

“Web Design for Developers” now available in Beta

Posted by Brian in News, Usability, Products, Projects, web (November 19th, 2008)

Web Design for Developers

My book Web Design for Developers is now available in Beta form.

You’ll learn how to design a web site from start to finish, and you’ll use many of the techniques and thought processes you’ve come to rely on as an application developer. You’ll learn some color theory, some typography basics, some XHTML and CSS, and how to incorporate Photoshop and Illustrator into a work flow that works for you, not against you.

You can buy an early copy and then contribute to the feedback cycle to help make this an even better book when it eventually ships. You can purchase the PDF and start reading now, or preorder the printed book which will ship after the beta process finishes up.

Fixing TextMate for Rails 2.0

Posted by Brian in Rails, tips, Testing (November 7th, 2008)

Rails 2.0 and above have some changes that break Textmate, a very popular development environment for Rails developers.

Running Tests

Rails 2.0 projects generate unit and functional tests with a relative require to test_helper. This change breaks
the Command-R (Run) and Command-Shift-R (Run Focused Unit Test) commands to fail since they can’t
include the necessary helpers. I finally spent a little time figuring this one out and the
answer is to modify the bundle commands themselves.

Open up the bundle editor, locate the Ruby bundle, and choose to edit the &lquot;Run&rquot; command.

Change it from

  export RUBYLIB="$TM_BUNDLE_SUPPORT/RubyMate${RUBYLIB:+:$RUBYLIB}"

to this:

  export RUBYLIB="..:$TM_BUNDLE_SUPPORT/RubyMate${RUBYLIB:+:$RUBYLIB}"

Now edit the &lquot;Run Focused Unit Test&rquot; command and make the same change.

Fixing incompatibilities with Builder

Rails 2.0 contains its own version of builder.rb. We have to take out the original one that TextMate provided
so our stuff starts working again.

mv /Applications/TextMate.app/Contents/SharedSupport/Support/lib/Builder.rb /Applications/TextMate.app/Contents/SharedSupport/Support/lib/Builder.rb.bak 

New Rails bundle

Open a new terminal and type this:

  cd "~/Library/Application Support/TextMate/Bundles"
  git clone git://github.com/drnic/ruby-on-rails-tmbundle.git "Ruby on Rails.tmbundle"

Slides from “Becoming a Documentation Ninja” from Twin Cities Code Camp V

Posted by Brian in News, docbook (October 13th, 2008)

Here’s the slide deck from the talk Chris Johnson and I gave at this year’s Twin Cities Code Camp. I had a great time talking about this and I wanted to make sure that all of the resources people need are easily available. The slide deck includes notes for each slide with links to relevant information.

Slides from “Becoming a Documentation Ninja” from Twin Cities Code Camp V in PDF format.

Enjoy, and if you’re missing important stuff from this or just want to learn more, leave a comment.

RSpec helped me refactor my code.

Posted by Brian in Rails, Howto, Testing (June 10th, 2008)

I’ve been extremely against using RSpec. I always found it rather clunky, but it turns out that resources to really help a person learn how RSpec works are dificult to find. The examples you find out on the web are just poorly written or just contrived and impractical, or they’re so hopelessly overengineered that a newcomer would be overwhelemed.

This weekend I took it upon myself to really learn RSpec and so I started rewriting some of the tests for FeelMySkills. I started with the Account model which is used all over the app. The account_id is stored in the session and I use the Restful_authentication plugin to get access to a current_account method which returns the Account object. I want to be able to determine whether or not that account is an Admin, and I have an entry in the roles called “admin”. Nothing too special about all this, as many apps use a similar bit of functionality.

To make this easy on myself, I wrote a method called is_admin? which returns true if the admin role is associated with my account and nil if it’s not, and as we all know, nil evaluates to false, and anything other than nil or false evaluates to true.

When an account is created, I give them a role called “user”. Eventually, Pro users will have a different role, giving them access to more stuff in the system. Here’s what i have so far:

  class Account < ActiveRecord::Base
    has_and_belongs_to_many :roles
    after_create :add_user_role
 
    def is_admin?
      self.roles.detect{|r| r.name == "admin"}
    end
 
    def is_user?
       self.roles.detect{|r| r.name == "user"}
    end
    
    def add_user_role
          self.roles << Role.user
 
    end
 
  end

So, when I create a new user, I need to make sure that user gets the user role. My original Test/Unit test looked like this:

  def test_new_account_should_have_user_role
    account = Account.create(:login => "test",
                                       :password=>"test",
                                       :password_confirmation => "test",
                                       :email => "test@test.com")
    assert account.is_user?
  end

This test passes without any issues, so I know the code is right. Here’s what I tried with RSpec:

  describe "when creating an account" do
    fixtures :accounts, :roles
    before(:each) do
      @account = Account.create(:login => "test",
                                           :password=>"test",
                                           :password_confirmation => "test",
                                           :email => "test@test.com")
    end
 
    it "should have the user role" do
      @account.is_user?.should be_true
    end
 
  end

Imagine my surprise when I ran this spec and it failed! The reason why makes perfect sense when you start thinking about it.

First, RSpec’s matcher be_true evaluates the response of the method to be equal to true. The code for is_admin? actually returns an instance of Role, and not true like I asserted earlier. While that method evaluates to true, it does not equal true. So it’s interesting that the assert method has no probelm making the evaluation, but RSpec’s matchers are pickier.

A fair argument here would be “why does your is_admin? method return a Role and not just true or false?” The answer is that I’m lazy. I rely on Ruby to work for me, and until now, #detect has been a great ally. In my controller code, I can do

if current_user.is_admin...

and all is well, without the need to explicitly return true or false from the is_admin? or is_user? methods.

A better way

Looking at the spec again, I notice that I am in fact asking for the role in that specification. So I rewrite it to grab the User role from the fixtures and ensure they’re equal and it passes.

    it "should have the user role" do
      @account.is_user?.should equal roles(:user)
    end

But something about that bothers me. What am I really testing? I’m testing to make sure that the account is a regular user. Maybe I really do need a method that returns true or false.

It turns out that if you have a method in your model that ends with a question mark (?) and returns true or false, then RSpec can dynamically create a matcher for it. I rewrote the spec like this:

 
    it "should be a user" do
      @account.should be_a_user
    end
 

and then added this method to my model:

   # calls is_user? and returns true if is_user? returns a result, 
   # or false if it returns nil
   def user?
      self.is_user? != nil
   end

and I ended up with something I am much more comfortable with. I think future refactorings might change this around even more, but I found this exploration to be extremely enlightening.

P.S. For those that are interested, I actually have several roles in my system and I don’t manually declare these methods like is_admin? and is_user? by hand. I use this instead:

class Account < ActiveRecord::Base
 
  # ...
    
    # constant containing all of the role names
    # in the system
    Role::ROLE_NAMES.each do |r| 
 
    class_eval <<-CODE
      def is_#{r}?
        self.roles.detect{|role| role.name == "#{r}"}
      end
      
      def #{r}?
        self.is_#{r}? != nil
      end
      
    CODE
  end
 
  #... 
 
end

That way I don’t need to add new methods when I implement factchecker or pro or business roles later. Just thought I’d share that.

Slides and Materials from “Web Design for Programmers”

Posted by Brian in News, web (June 4th, 2008)

The slides from my RailsConf 2008 tutorial session are now available. Grab the PDF version.

Unfortunately, the handouts I sent were printed in black and white so some of the color examples don’t work as well. Grab color ones instead.

If there are additional materials from the presentation that you want to see, let me know and I’ll see what I can do.

Create a new Edge Rails project

Posted by Brian in News, Rails, snacks (April 24th, 2008)

In a previous post, I provided scripts that made the creation of a new Edge Rails project easy. Since then, Rails has moved from Subversion to Git, which means that the scripts I provided no longer work as expected. Fortunately, very little has changed and I was able to make the script a little bit better so that it acts like the original rails command.

Prerequisites

First, you’re going to need git. I could have written the script to grab the latest version via a zipfile, but I wanted something that was fast and worked on all platforms. Windows can unzip files, but then I’d have to make Windows users go grab commandline tools to unzip files.

Installing Git

Mac users with XCode and Macports installed can do it with

sudo port install git-core +svn

Windows users can install Msysgit.

Linux users should install Git using their package manager or from source.
Here’s the script. Instructions for running it are after the code.

#!/bin/ruby
git_repo = "git://github.com/rails/rails.git"

help = %Q{
Rails Info:
    -v, --version                    Show the Rails version number and quit.
    -h, --help                       Show this help message and quit.
 
General Options:
    -p, --pretend                    Run but do not make any changes.
        --force                      Overwrite files that already exist.
    -s, --skip                       Skip files that already exist.
    -q, --quiet                      Suppress normal output.
    -t, --backtrace                  Debugging: show backtrace on errors.
 
Description:
    The 'edge_rails' command creates a new Rails application with a default
    directory structure and configuration at the path you specify, using the
    very latest version of Rails.
 
Example:
    edge_rails ~/Code/Ruby/weblog
 
    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
    See the README in the newly created application to get going.    
 
}

require 'fileutils'
 
if ARGV.empty?
  puts help
  exit
end
 
dir = ARGV.shift
args = ARGV.join (" ")
 
FileUtils::mkdir(dir)
FileUtils::mkdir("#{dir}/vendor")

puts "Exporting EdgeRails from #{git_repo}"
# system "svn export http://svn.rubyonrails.org/rails/trunk #{dir}/vendor/rails"
system "git clone --depth=1 #{git_repo} #{dir}/vendor/rails"
system "rm -rf #{dir}/vendor/rails/.git*"
 
system "ruby #{dir}/vendor/rails/railties/bin/rails #{dir} #{args}"

How this works for Mac and Linux users

Save the script to your home folder as edge_rails, and set the execute bit:

  chmod 644 ~/edge_rails

Run it with

  ~/edge_rails your_app

You could symlink it to your /usr/local/bin if you are feeling clever.

How this works for the Windows crowd

Save this script as c:\ruby\bin\edge_rails.bat

@echo off
goto endofruby
#!/bin/ruby
git_repo = "git://github.com/rails/rails.git"

help = %Q{
Rails Info:
    -v, --version                    Show the Rails version number and quit.
    -h, --help                       Show this help message and quit.
 
General Options:
    -p, --pretend                    Run but do not make any changes.
        --force                      Overwrite files that already exist.
    -s, --skip                       Skip files that already exist.
    -q, --quiet                      Suppress normal output.
    -t, --backtrace                  Debugging: show backtrace on errors.
 
Description:
    The 'edge_rails' command creates a new Rails application with a default
    directory structure and configuration at the path you specify, using the
    very latest version of Rails.
 
Example:
    edge_rails ~/Code/Ruby/weblog
 
    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
    See the README in the newly created application to get going.    
 
}

require 'fileutils'
 
if ARGV.empty?
  puts help
  exit
end
 
dir = ARGV.shift
args = ARGV.join (" ")
 
FileUtils::mkdir(dir)
FileUtils::mkdir("#{dir}/vendor")

puts "Exporting EdgeRails from #{git_repo}"
# system "svn export http://svn.rubyonrails.org/rails/trunk #{dir}/vendor/rails"
system "git clone --depth=1 #{git_repo} #{dir}/vendor/rails"
system "rm -rf #{dir}/vendor/rails/.git*"
 
system "ruby #{dir}/vendor/rails/railties/bin/rails #{dir} #{args}"
__END__
:endofruby
"%~d0%~p0ruby" -x "%~f0" %*

Now, open a new command prompt and type

edge_rails my_new_app

If it doesn’t work, check that you have Git installed properly and have added Git’s command line utilities to your path.

Reverse Proxy Fix 1.0.5.0 released

Posted by Brian in News, Rails, Products (March 7th, 2008)

The reverse_proxy_fix plugin allows a Rails application to live behind a proxy like the one provided by HeliconTech’s ISAPI_Rewrite plugin as outlined in Deploying Rails Applications. It allows you to configure the base URL that will be prepended to any URL generated by the Rails link_to method and friends. This is useful if you want to force all requests through a frontend or if you want to graft your Rails application onto an existing IIS URL scheme.

This release fixes an issue with named routes and Rails 2.0. Previous versions of the plugin did not support rewriting of named routes in Rails 2.0 due to the optimization code for named routes. This version of the plugin disables the optimizations.

Installation

Installation is simple:

  ruby script/plugin install http://svn.napcsweb.com/public/reverse_proxy_fix

Then provide your base URL, which is the URL you want prepended to all of your URLs. For example, if you are trying to mount your Rails application at http://www.mydomain.com/myapp, you’d enter that as your base URL.

Next you need to specify which version of Rails you are using.

Comments are welcome, and so are patches if you see something that doesn’t make sense.

Working with Docbook on Windows

Posted by Brian in Howto, snacks, tips (March 3rd, 2008)

Setting up a toolchain for working with Docbook on Windows often requires setting things up using Cygwin. Many people are just simply not willing to do that. This tutorial will show you how to set up a native environment to work with Docbook, and show you how to make CHM and PDF files on Windows.

Thanks to http://supportweb.cs.bham.ac.uk/documentation/tutorials/docsystem/build/tutorials/docbooksys/segmentedhtml/ch03s03.html#DocBookSys-Chapter3-XML-Install-libxml-Windows for much of this information.

Getting the tools

The tools you need to work with Docbook XML and XSTL are all available on Windows. The first thing you need to do is visit http://www.zlatkovic.com/pub/libxml/ (new window) and grab the latest versions of

  • libxml2
  • libxslt
  • iconv

Download each and unzip the contents of the folder to c:\windows or another location on your path. For reference, these files are the ones you’re looking for:

iconv.exe
libexslt.dll
libxml2.dll
libxslt.dll
xmlcatalog.exe
xmllint.exe
xsltproc.exe

If you feel better about putting these in their own folder, that’s fine as long as you add the new folder to your path.

Getting the Stylesheets

In order to build a book, you need to have the XSLT stylesheets so you can transform your XML into a pretty-looking book with a table of contents and nicely formatted text.
Download the docbook-xml-ns files from sourceforge: http://sourceforge.net/project/showfiles.php?group_id=21935

Unpack to your c:\ drive and then rename the extracted folder to c:\docbook-xsl

Generating PDFs

In order to create a PDF, you have to first convert to the FO format and then use a Java library to convert the FO to a PDF. Apache FOP does this for you. You’ll need to have a JRE (Java Runtime) installed though. Visit http://java.sun.com/ for that.

Get FOP to build PDFs

Download FOP at http://www.uniontransit.com/apache/xmlgraphics/fop/fop-0.94-bin-jdk1.4.zip and unzip it to a temp location. Copy all .jar files in build/ and lib/ to your Java installation’s lib/ext folder. On my system it’s C:\Program Files\Java\jre1.5.0_11\lib\ext. Your system will differ depending on your installed version of Java.

Next, download OFFO-hyphenation from http://offo.sourceforge.net/index.html and grab the offo-hyphenation-fop-stable.zip file from the downloads page and put the jar files in the same folder as the FOP files.

Building your first book

Create a project folder called “my_book” and create a new file called “book.xml” in this folder.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
                 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<book>
  
  <bookinfo>
  <title>My Simple Book</title>
  </bookinfo>

  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="chapter1.xml"/>
 
</book>

Then create a chapter for your book. Create the file chapter1.xml in your project folder with this content:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
                 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
 
<chapter id="chapter1">
  <title>Introduction</title>
  <para>This is just a simple book.</para>
 
</chapter>
 

Notice that the chapter and book each have their own doctype, This is really important. Each chapter file needs to have this structure in order to work properly.

Generating HTML from the document

The easiest way to use Docbook is to export to HTML. Execute this command to create an HTML version of your book:

   xsltproc --xinclude --output book.html c:/docbook/xsl/html/docbook.xsl book.xml

Creating a makefile to build the PDF

The PDF creation process is similar to the HTML process but it does require two steps. You need to first convert the document to the FO file format. Then you use FOP to convert it to the PDF. We can automate this by using Ruby.

Create a Ruby file in your project folder called “make”. You’ll use this file to build the PDF of your book.

file = ARGV[0]
cmd1 = "xsltproc --xinclude --output #{file}.fo c:/docbook-xsl/fo/docbook.xsl #{file}.xml "
cmd2 = "java org.apache.fop.cli.Main -fo #{file}.fo -pdf #{file}.pdf"
 
puts "Building FO file"
`#{cmd1}`
 
puts "Building PDF"
`#{cmd2}`
 
puts "Cleaning up"
`del #{file}.fo`
 
puts "Done"
 

Now, build your book:

ruby make book

Creating a Help File

Generating a Windows HTML Help file (CHM) is pretty similar to the way you make a PDF. You first need to make the HLP file using xsltproc, and then you use a commandline tool to build the CHM.

Grab a copy of Microsoft’s HTML Help Workshop here and install it. Open a command prompt and copy the hhc file to the c:\windows directory so that the file is on your path.

copy "c:Program FilesHTML Help Workshop"hhc.exe c:windows

Next, we can use Ruby to make a file to create another build file. Create a file called “make_chm” in your project folder.

file = ARGV[0]
cmd1 = "xsltproc --xinclude c:/docbook-xsl/htmlhelp/htmlhelp.xsl #{file}.xml"
cmd2 = "hhc htmlhelp.hhp"
 
puts "Building HLP temporary files"
`#{cmd1}`
 
puts "Building CHM"
`#{cmd2}`
 
puts "Cleaning up"
`rename htmlhelp.chm #{file}.chm`
`del *.hhp`
`del *.hhc`
`del *.html`
 
puts "Done"
 

Summary

Docbook is a really great way to create books, tutorials, and documentation in a format that can be transformed into various other formats. It’s extremly easy to work with in Windows too!

Next Page »