Using Rack to Combine Sinatra and Word Press

June 2 2009 by railsdog

There’s been a lot of buzz recently around the lightweight Ruby framework known as Sinatra. It seems ideally suited for simple web applications that require a little sprinkle of Ruby and using the entire Ruby on Rails stack might be overkill. You’ve probably also heard of Rack (unless you’ve been without Internet access for the past six months.) If you’re new to Rack and would like to learn more, you can check out this excellent presentation from RailsConf. I recently had the need to build a website that featured a blog along with some minimal dynamic content so I thought I would try hooking up Sinatra together with the Word Press blog engine.

WordPress(WP) is an excellent blogging platform. Its the consensus tool of choice for professional bloggers (those who blog for a living as opposed to people like me who occassionally blog about technology.) Since I was really happy with WP and I believe in using the best technology for the job, I wanted to see if I could get it working alongside Sinatra which I planned to use for the rest of the site. Why not just do the whole thing in PHP? Well the answer is that I hate programming in PHP. I didn’t mind using an excellent tool like WP but I didn’t want to get carried away with the PHP when it came to my own coding.

First, you need to get WP up and running with Apache HTTP Server. You can use any server really but I would recommend Apache since its widely used and well documented when it comes to PHP applications. There is no shortage of WP setup documentation so I’m not going to cover it here. Just be sure to setup WP in its own directory (/blog) instead of the top level root directory. Once you can reach your WP blog via http://example.com/blog then you’re ready to proceed.

You’re also going to need to install Phusion Passenger. I’m not going to cover installation of Passenger either since most Rails developers are already familiar with it. If you’re not, I suggest you read some of the excellent documentation on the subject. What you may not know, however, is that Passenger also supports arbitrary Ruby web appications that follow the Rack interface (like say … Sinatra.) So lets get started with a simple Rack app and then move onto Sinatra.

Install the Rack Gem

Lets make sure the rack gem is installed on our server.


gem install rack

Create the Directories Required by Rack

Suppose we are creating an application called example which is located in the /webapps directory


mkdir /webapps/example/public
mkdir /webapps/example/tmp

Create a Basic Rackup File

We also need to create a /webapps/example/config.ru for starting the Rack application


app = proc do |env|
    return [200, { "Content-Type" => "text/html" }, "hello world"]
end
run app

Change the Document Root

In the Apache config you will want to configure the DocumentRoot to point to the public directory in your Rack app (/webapps/example/public). Leave your WP blog directory where it is for now. Restart Apache.

If you navigate to your application in a web browser you should see the familiar “hello world” greeting. This means Phusion and Rack are now working together without a problem. Lets add Sinatra to the mix.

Setup Sinatra

Install the Sinatra gem if you haven’t done so already.


gem install sinatra

Replace your config.ru with one that will setup Sinatra


require 'rubygems'
require 'sinatra'

Sinatra::Application.default_options.merge!(
  :run => false,
  :env => :production,
  :views => '/webapps/example'
)

require 'app.rb'
run Sinatra.application

Now create an app.rb which will be the basis for your Sinatra app


get '/' do
  'Hello Sinatra!'
end

Restart Apache and navigate to your local application using your web browser you should now see the Sinatra greeting that we just added.

Add the WP Blog

Move your entire blog dir into your Sinatra public directory. So you will now have /webapps/example/public/blog along with the original .htacess file used by WP. Your blog won’t work yet, there’s an important tweak to be made to your httpd.conf


<Location /blog>
  PassengerEnabled off
</Location>

This tells Passenger not to bother with files in the blog directory. This is key to getting the PHP-based WP blog to run inside of a directory where everything else is Sinatra. If you test your application inside of a web browser the blog should be working!

Build Out Your Sinatra Application

Go ahead and build out the rest of your Sinatra application now. Most likely you’re going to want to share a common layout, header and footer between your Sinatra application and your WP blog. You can add “partial” support in Sinatra using a helper (Sinatra does not explicitly support partials.)

Modify your app.rb as follows:


get '/' do
  @section = 'overview'
  erb :overview, :layout => :default
end

helpers do
  # Usage: partial :foo
  def partial(page, options={})
    erb page, options.merge!(:layout => false)
  end
end

Then you can create a default.erb to serve as the default layout.


<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head profile="http://gmpg.org/xfn/11">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="Shortcut Icon" type="image/ico" href="/blog/wp-content/themes/spree/favicon.ico" />
  <title>Spree</title>
  <link rel="stylesheet" href="/blog/wp-content/themes/spree/style.css" type="text/css" media="screen" />
</head>
<body>
  <div id="page">
    <!-- BEGIN: Header -->
    <%= partial :header %>
    <!-- END: Header -->
    <div id="main">
      <div class="content">  
        <p>
          <%= yield %>
        </p>
      </div>
    </div>
    <!-- BEGIN: Footer -->
    <%= partial :footer %>
    <!-- END: Footer -->
  </div>                 
</body>
</html>

Notice how I am using the favicon and stylesheets right from the WP blog theme. From this point on we’re just writing a nice Sinatra application and sharing styles and images with our WP blog.

Final Thoughts

This is an excellent way to build a simple Ruby based website that requires a blog. I started off by having my artist just work up a design for the WP blog since she could do that on her own without any Ruby. I then copied the header and footer into my Sinatra app and created some stub ERB files for her to edit. Sinatra worked out well for my very simple needs. I basically needed a simple way to share layouts and to highlight the current navigation tab in my header.

My artist was able to edit these ERB files in place because they were basically straight HTML. All of the dynamic stuff was contained in the layout itself. The end result is a seamless integration of Ruby + PHP where each technology is being used for what it does best.

A Public “Thank You”

May 6 2009 by railsdog

@GreggPollack put together an excellent RubyHeroes presentation before the keynote.  In addition to recognizing some of the great contributions these individuals made, Gregg suggested that we all take a moment to thank at least three people whose work has made our lives that much easier.  So instead of getting caught up in minor complaints about the accomodations or speeches, I decided to throw out some more positive energy.

  1. GitHub - I’m not going to waste a lot of space talking about how much of an impact GitHub has made on the Rails community.   Its not like these guys are toiling away in anonymity but their contribution has been so important that I’m just going to go on record as saying “Thanks.”

  2. Phusion - Again, everyone knows what these guys have done for simplifying Rails deployment.  Just because they get plenty of “Thank Yous” doesn’t mean I can’t throw my own two cents in here.  I also had the opportunity to thank one of the Phusion guys in person at dinner this evening.

  3. ResourceController - James Golick’s plugin finally convinced me to embrace REST.  If you’re not familiar with it, its a great way to simplify the implementation of your standard RESTful controller.  My controllers became way more DRY as a result.  Again, saw James at dinner and shook his hand in person but it doesn’t hurt to say it here.

Honorary Mentions:

  • DHH and RailsCore for Rails (DUH)
  • Chad Fowler and company for organizing RailsConf
  • Gregg Pollack for the Ruby Heroes presentation, conference videos and the entertaining RailsEnvy podcasts (along with Jason Seifer.)

RailsConf Kicks Off

May 6 2009 by railsdog

Well today was the first day of talks here at RailsConf.  DHH kicked things off with an opening speech.  He spent some time talking about Rails 3.0 features but unfortunately it was hard to follow the slides in the back.  Somebody on #railsconf thought it would be cool if you could broadcast slides to everyoene’s laptop during the live talk.  That would have come in handy for this.

The talk was good despite the sound and slide difficulties.  I always enjoy hearing how other programmers approach the challenges of their job.  DHH was talking about how “renogiation of requirements” can ultimately lead to a huge productivity gain.  He described a time at 37 signals where he spent two weeks trying to solve an impossible task.  He ultimately came up with a much simpler solution and proposed it to the client.  Client was indifferent (”Sure, whatever”) and he was done in 48 hours.

The talks this morning have been pretty good so far.  Mercifully there is no smoking in the conference center so that is a welcome change of pace from the rest of the hotel.  My main complaint so far would be that the chairs have metal backs with no cushion so they’re extremely uncomfortable.

One last thing I would like to mention is the state of the Rails community.  There are lots of first time RailsConf attendees here this year which is a great sign.  People also seem to be mixing a lot better instead of hanging out exclusively with the people that they came here with.  The Rails community really seems to be moving in a more positive direction, despite minor flare ups and distractions along the way.

I really think the whole Rails - Merb merger sets a good example for how much everyone stands to gain when setting aside ego and just work together to write the best possible software.  Constructive criticism is fine but collaboration is even more productive.

Vegas: First Impressions

May 5 2009 by railsdog

I’ve been in dozens of airports around the world but stepping off the plane at LAS conveys the immediate impression that you have arrived somewhere different.  The first thing you see as you come out of the jetway are tons of slot machines.  I have nothing nice to say about the airport ground transportation options.  I used the 30 minute ride to my hotel (which was like 5 miles from the airport) to come up with about half a dozen ways to design a better system.  You can start by knocking down the worthless fucking monorail that they have and replace it with a proper light rail system that would actually connect people to the one place everyone wants to go - the airport!

Went out last night with @hackerchic, @tunagami and Sonny (twitter account not shown.)  Took the afore mentioned monorail to the MGM where we had a good time at the Centrifuge bar.  Every 20 minutes or so some dance song would come blasting on and the bar tenders would all jump up on the bar and start dancing.  So that seemed to be a pretty authentic Vegas experience.

Cigarette smoking is completely out of hand here.  I’m really not used to people smoking indoors and it seems to be everywhere.  My eyes and throat are really irritated from all of the second hand smoke.  On the plus side, you can drink beer anywhere you want (including in the middle of the street.)  Its kind of strange to be drinking a beer while in line to check in to your hotel (next to the guy smoking a cigarette.)  Even stranger is the notion of just walking outside with a giant 32 oz. beer in your hand.

Five Reasons To Go to RailsConf

April 15 2009 by railsdog

RailsConf is less than three weeks away now but there is still time to sign up if you’re interested in coming. With the recent reduction in the hotel price ($99) it might be worth considering. Here are a few more reasons to go this year in no particular order:

  1. Excellent Speakers — Last year was my first RailsConf and I was blown away by the quality of the speakers. Pretty much every single session had both an interesting topic and an engaging speaker. Some sessions are better than others, but overall I think the speaker quality was quite high. The slides are always available online and usually very high-quality.
  2. Convenient Location — This year the conference will be held in Las Vegas, Nevada for the first time. Las Vegas is easy to get to from almost anywhere in the United States. There really isn’t a better location in terms of the sheer number of direct flights other than perhaps Orlando Florida. The conference will also be held in the actual hotel where attendees will be staying. With an action-packed schedule this really adds to the convenience since you won’t be traveling back and forth from the hotel to the conference center like last year. It’s all right there under one roof.
  3. Hiring Opportunities — At last year’s RailsConf there was a shocking number of companies who were interested in hiring qualified Rails programmers. Every time I sat down there was some brochure or business card laying there mentioning that such and such a company was looking to hire. So if you’re looking to switch jobs or to find out more about the kinds of jobs that are out there this is a great opportunity.
  4. Creativity Boost — RailsConf is also a great opportunity to come up with new ideas and inspiration for your next 12 months of programming. With all the great talks and ideas floating around your head will soon be buzzing with exciting new ideas to take back to your existing job. It’s a great opportunity to take a break from the daily coding march and to gain some new perspective.
  5. A Chance to Network — The conference is also a chance to meet all those people you have been chatting with online over these past several months. All of your favorite bloggers will be there plus those people whom you’ve been working with on your favorite open source projects. It’s fun to put a name with a face and have more in-depth discussions that are not really possible online.

So if you haven’t already signed up for RailsConf go and do it now. It’s definitely worth the time and money.  If you decide to go, make sure to say “hi” if you see me there.

Custom Bash Prompt for Git Branches

March 7 2009 by railsdog

example of git bash prompt

git bash prompt

If you are an active git user then you may find yourself constantly switching between different branches in the same project as you are working. If you’re not doing this, you’re probably not experiencing the full power of git. I recently added some functionality to my bash prompt that shows the current git branch in green and a yellow asterisk if there are uncommitted changes in the project.

Here’s how to do it. First you will need a copy of .gitcompletion.sh in your home directory. This script has some functions that we will use to customize the bash prompt. It also has some nice side effects like tab completion for branch names, etc. Now simply add the following to your .bashprofile


source ~/.git_completion.sh

function parse_git_dirty {
  [[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
}

function parse_git_branch {
  git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/[\1$(parse_git_dirty)]/"
}

export PS1='\h:\W$(__git_ps1 "[\[\e[0;32m\]%s\[\e[0m\]\[\e[0;33m\]$(parse_git_dirty)\[\e[0m\]]")$ '

GitHub Search Tip

February 2 2009 by railsdog

GitHub recently made significant changes to their search functionality. I often use their search to look for related projects, such as new Spree extensions. Prior to these changes I would simply search on spree. Now when you do this the default results are IMO less then desirable.

So if you’re like me and you just want to find projects containing your search term then I have a tip for you. Just add fork:false to your search and it will exclude all of the forks from your results. This makes it much eeasier for projects like Spree where there are 60+ forks that you would have to sift through in order to find what you’re really looking for.

Rails Commerce App in Ten Minutes

November 26 2008 by railsdog

In today’s blog post, I show you how to get a Ruby on Rails based commerce app up and running in ten minutes. We’ll be using the Heroku (think Rails cloud) as the hosting service and Spree as the commerce platform.

Prerequisites

The “10 minute” claim assumes you already have a Heroku account and that you have , Ruby, Rails 2.1.2 and Gems installed locally.

You will also need to have git installed and a public ssh key. If you’ve been doing Rails development on a Mac or other Unix type system this shouldn’t be new to you. If for some strange reason you haven’t started using git yet, you need to do yourself a favor and look into it.

Step 1. Grab the heroku and spree gems.


sudo gem install heroku
sudo gem install spree

Step 2. Create the store

Use the Spree gem to create the store locally


spree footore

You will need to pick a unique name for your store for heroku so don’t call it foostore since that is already taken.

Step 3. Place your store under git source control

Heroku uses git to manage its deployment. So put your new Spree app under source control.


cd footore
git init
git add .
git commit -m "First commit."

Step 4. Unpack Gems

Heroku doesn’t seem to want to use its own gem repository. No worries, just unpack the gems that Spree requires using


rake gems:unpack
git add vendor/gems
git commit -m "Unpacked gems."

Spree itself also needs to be unpacked


rake spree:freeze:gems
git add vendor/spree
git commit -m "Froze Spree 0.5.0"

Step 5. Tweak the Rails Version

Unfortunately Heroku only supports certain Rails versions and they tend to lag behind the latest. Spree requires Rails 2.1.2 but Heroku only works with Rails 2.1. So we just need to modify Spree to work with Rails 2.1 instead.

Edit config/boot.rb and replace

load_rails("2.1.2")

with

load_rails("2.1")

Now commit these changes


git add config/boot.rb
git commit -m "Switch to Rails 2.1

Step 6. Add the store to Heroku


heroku create foostore

The first time you add an app into Heroku it will ask you for the email address and password associated with your Heroku account. Interestingly, the heroku gem also copies your public ssh key up to heroku so that you can authenticate with your private key going forward.

Remember to choose a unique name for your store since apparently Heroku requires all applications to have a unique name (otherwise it will warn you that the name is already taken.)

Step 7. Push to Heroku


git remote add heroku git@heroku.com:foostore.git
git push -f heroku

Through the magic of Heroku, your application is now deployed! It takes a while to run the migrations but you should get there eventually.

The git remote add and -f stuff is a onetime deal. Going forward you can update with just git push.

Step 8. Make the store public

The store is now technically deployed on Heroku but its not yet publicly visible. Using your browser you need to log into your Heroku account.

Click the “settings” link and the select the radio button to make it public as well as the radio button at the bottom to run in the much faster “production” mode. Heroku has some interesting abilities to edit online but I’m a big fan of local development on Textmate so I have no use for the development mode.

That’s it. You can now hit your webapp at http://foostore.heroku.com. Be sure to login (username: admin password: spree) and change the default password to something more secure.

There are several intersting aspects of Heroku which I’ll save for another blog post. One interesting thing I’ll mention here is the ability to run rake commands on the remote server in your local shell.

Conclusion

Well now you have your online store up and it only took you ten minutes (or so.) Time to show it to your prospective client and lock down that contract! Best part is that this cost you nothing (at least for now while Heroku is still free.)

Using paginating_find with acts_as_xapian

October 16 2008 by railsdog

On a recent project I came up with a cool way to do paginating find with my resources. I was able to combine resource_controller with acts_as_xapian for very DRY searching.

I simply override the collection method in the index view and I can then display a list of requests, eighteen per page, that are sorted by spec.


class RequestsController < ResourceController::Base
  include SearchableResource
  ...
  private
  def collection
    search_collection(:spec, {}, size=18)
  end
end

The bulk of the interesting code is in the SearchableResource module that is included by all of the controllers that need searching.


# Adds a collection method to a resource controller that
# is suitable for collections that can be optionally searched
module SearchableResource
  def self.included(base)
    base.class_eval {
      def clazz
        object_name.camelize.constantize
      end

      def filter_criteria
        return "" unless @search_filter
        return " #{@search_filter.query}"
      end

      def search_collection(order_by, find_options = {}, page_size=6)
        @search = params[:q] ||= ""
        @query = @search + filter_criteria
        if @query.blank?
          session[:query] = nil
          options = {:order => order_by, :page => {:size => page_size, :current =>params[:p], :first => 1}}
          options.merge!(find_options)
          @collection ||= end_of_association_chain.find(:all, options)
          @collection.sort
        else
          session[:query] = @query
          current_page = params[:p].to_i if params[:p]
          current_page ||= 1
          hits = ActsAsXapian::Search.new [clazz], @query, :limit => 1
          @collection = PagingEnumerator.new(page_size, hits.matches_estimated, false, current_page, 1) do |page|
            offset = (current_page -1) * page_size
            hits = ActsAsXapian::Search.new clazz, @query, :limit => page_size, :offset => offset
            # pull the models out of the results
            collection = []
            hits.results.each do |hit|
              collection << hit[:model]
            end
            collection.sort
          end
        end
      end
    }
  end
end

The only other trick is to modify resource_controller so that you can use the url helpers with parameters. This allows a single partial for the pagination that takes the search query as a parameter. But that’s a subject for another post.

Listing Search Terms With Xapian

September 17 2008 by railsdog

I’m currently using Xapian for a client project and I needed to get the list of search terms for a given model. The idea was to present the user with a tool tip type window listing the possible valid search terms. Since the search bar was actually a parital and used for many different models, I wanted to dynamically discover the relevant search terms.

Here’s the simple way to get an array of the human readable search terms for the Project model:

Project.xapian_options[:terms].collect { |term| term[2] }

Since I was also using resource_controller, I was able to DRY this up nicely.


def search_terms
  clazz = model_name.camelize.constantize
  terms = clazz.xapian_options[:terms].collect { |term| term[2] }
  terms.sort
end