I just finished implementing full-text searching in a Rails project with Xapian. It was actually pretty painless and works very well. I did run into one little snag. It didn’t work in production.

For this particular project, the app is running in an Apache + Passenger environment. After I completed the installation of Xapian, I deployed my updated version of the app and tried out the search only to be returned an error.

ArgumentError (Wrong arguments for overloaded method 'Enquire.mset'.
Possible C/C++ prototypes are:
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount checkatleast, Xapian::RSet const *omrset, Xapian::MatchDecider const *mdecider)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount checkatleast, Xapian::RSet const *omrset)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount checkatleast)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount checkatleast, Xapian::RSet const *omrset, Xapian::MatchDecider const *mdecider, Xapian::MatchDecider const *matchspy)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::RSet const *omrset, Xapian::MatchDecider const *mdecider)
    Xapian::MSet Enquire.mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::RSet const *omrset)
):

After some searching, I came across something helpful in the acts_as_xapian Google group.

If your issue is the same as mine, you will have to modify line 206 in
acts_as_xapian/lib/acts_as_xapian.rb.

If yours looks like this:

limit = options[:limit] || -1; limit = limit.to_i # -1
means all matches?

you will want to replace the “-1″ with a different number.  I changed
mine to 1000.  This just sets the default limit for searches.

We had wanted to set it to where there was no default limit unless it
was specified in the program and Francis thought “-1″ would do that.
Unfortunately, it did not.

Another way to fix (assuming this is your issue) is to just add
a :limit in your search:

@search = ActsAsXapian::Search.new([Lesson], “search
term”, :limit=>20)

I opted to not make a change to the actual plugin. Instead, I followed the latter advice of adding “:limit => 1000″ to my ActsAsXapian::Search call. This worked for me because the content being searched doesn’t change in count often and there are only a few hundred records.

For more help getting Xapian full-text searching rocking in your Rails app, try some of these great links.

A couple of weeks ago, I launched a freelance site on Dreamhost. The site was a pretty basic Ruby on Rails application: a custom CMS, mp3 uploads and podcast feeds, and Vimeo integration (more on that in a later post).

The client chose Dreamhost prior to my involvement with the project. While I prefer Slicehost, I did some reading through Dreamhost’s wiki and knowledge base and felt pretty good getting a Rails app up and running in their shared hosting environment. I was wrong! What should have been about hour’s worth of work ended up being an all day event. Watch out! Fresh from the garden, here are some tips to help your deployment to Dreamhost go as smooth as possible.

I will divide these steps into 3 sections, or work areas: Dreamhost Panel, Dreamhost Shell, Local Box

Dreahost Panel

Domain Setup

  1. Login to your Dreamhost panel.
  2. Click “Domains” , select “Manage Domains”, and then click “Edit” on the domain you want to host your Rails app. Note, if you already have a domain on your Dreamhost account, you just need to edit the settings. Otherwise, you will need to add a domain (I will not detail this process b/c it is out of the scope of this post.
  3. Make sure to select the checkbox for Ruby on Rails Passenger
    Dreamhost Passenter Checkbox

    Dreamhost Passenger Checkbox

  4. Select the “user” you want to run the app
  5. Look for “Specify your web directory:” and put in “appfolder/current/public”. Note: the “current/public” addition is extremely important if you are using Capistrano.
  6. Click “Change fully hosted settings now”

Mysql Setup

  1. Click “Goodies” and then “Manage Mysql”
  2. Add a database through the easy to use form. Take note of the name of the database, the database username, and the database host name.

Setup User

  1. Click “Users”, them “Manager Users”
  2. Look for the user that is going to run your app (this should have been created in domain setup) and make sure the type is set to “Shell”.
  3. If it’s not, click “Edit”, select “Shell” for User Account Type, and click save changes.

Dreamhost Shell

  1. Login to your fresh shell account with your newly updated user.
  2. Add the following lines to your “.gemrc” file.
:gempath:
- /home/USERNAME/.gems
- /usr/lib/ruby/gems/1.8
:gemhome: /home/USERNAME/.gems

Local Box

  1. Update your database.yml file with your production database info
  2. Update your environment.rb file to contain the following line. I put it just below the RAILS_GEM_VERSION
  3. ENV['GEM_PATH'] = File.expand_path(’~/.gems’) + ‘:/usr/lib/ruby/gems/1.8′
  4. Write your Capistrano script
set :domain, "DREAMHOST_SERVER"   #the one you ssh into
set :user, "DREAMHOST_USER"            #the user you created when setting up the domain (has to have shell access)
set :application, "APPLICATION"          #the name of the folder you chose when setting up the domain
set :applicationdir, "/home/#{user}/#{application}"  # The standard Dreamhost setup
 
set :repository, "YOUR_GIT_REPO"
set :scm, :git
 
# deploy config
set :deploy_to, applicationdir       # Where on the server your app will be deployed
set :deploy_via, :remote_cache
 
# additional settings
default_run_options[:pty] = true  # Forgo errors when deploying from windows
#ssh_options[:keys] = %w(/Path/To/id_rsa)            # If you are using ssh_keys
set :chmod755, "app config db lib public vendor script script/* public/disp*"
set :use_sudo, false
 
role :app, domain
role :web, domain
role :db,  domain, :primary => true
 
#Passenger stop, start, and restart calls
namespace :deploy do
  desc "Restarting mod_rails with restart.txt"
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{current_path}/tmp/restart.txt"
  end
 
  [:start, :stop].each do |t|
    desc "#{t} task is a no-op with mod_rails"
    task t, :roles => :app do ; end
  end
end

From this point, you should be able to run any of the Capistrano tasks (cap deploy:setup, cap deploy:cold, cap deploy:migrations, etc) and install any gems you may need for your app. You may run into some permissions errors when you first start running the cap taks, but you should be able to ssh into your account and correct them.

PLEASE NOTE! This is buy no means intended to be a complete walkthrough, it is merely a guide and personal reference for some of my trouble spots.

Today, I had a small problem with a gem. It all started when I upgraded my Ruby installation to 1.8.8 and suddenly couldn’t install gems. So I went back to 1.8.7.

After reverting to the older version back, I tried to install a gem, but got an error message.

WARNING:  Installing to ~/.gem since /usr/local/lib/ruby/gems/1.8 and
/usr/local/bin aren't both writable.
WARNING:  You don't have ~/.gem/ruby/1.8/bin in your PATH,
gem executables will not run.

WAIT! That’s no good. DOH! I forgot the “sudo”. A gem that won’t run is no good. And I don’t really want gems in random folders all over my system.

So I give it the old…

gem uninstall jsmin

… only to get back….

ERROR:  While executing gem ... (Gem::InstallError)
Unknown gem jsmin >= 0

FAIL!

Naturally, I did what every other over-reactive personality type would do.

rm ~/.gem/ruby/1.8/gems/jsmin-1.0.1.gem

Success! But wait, it’s still showing up in my gem list. So after doing some digging I found a handy little command.

First, I had to restore the gem from the ~/.gem/ruby/1.8/cahe. Then, run this little beauty.

gem uninstall jsmin -i ~/.gem/ruby/1.8/

The Moral of the story is… the -i option in rubygems will allow you specify an installation directory.

Here is a part of a support form used to submit a trouble ticket to an unnamed popular web host. I could not stop laughing.

<label for="severity">Please select the type of this request:</label>
<select id="severity" name="severity"> 
<option value="0">Just a casual question, comment, idea, suggestion...</option>
<option value="1">I need some help but it's not super time-sensitive.</option> 
<option value="2">I can't get things done until I hear back from you, please reply ASAP.</option> 
<option value="3">Things are broken and I'd like them not to be!</option> 
<option value="4">OMG! EXTREME CRITICAL EMERGENCY!! EVERYTHING'S BROKEN! People are DYING</option> 
</select>
 
<label for="expertise">Please select your general expertise in the area of this request:</label>
<select id="expertise" name="expertise"> 
<option value="1">Please explain everything to me very carefully.</option> 
<option value="2">I do know some stuff, but please don't assume too much.</option> 
<option value="3">Overall I know my stuff, but I'm a little shaky in this area.</option> 
<option value="4">I have a good understanding of this stuff.</option> 
<option value="5">Not to be rude, but I probably know more about this than you!</option> 
</select>

I will blog.

March 24th, 2009

I am relaunching my personal blog with an attempt to whittle down the niche a bit. From this point on, I will be sharing tips, news, and odds/ends from the world of web development. You can look out for interesting tidbits on Rails, Slicehost, jQuery, Flash, CSS, and anything else that I feel like sharing.

Thanks for stopping by.