Close and Go BackBack to Viget

Tips and Tricks

Effectively Using Git With Subversion

Clinton R. Nixon
Clinton R. Nixon, Senior Developer, April 18, 2008 9

Like many organizations using Rails, we have caught the git wave, and are in a state of transition between git and Subversion. Our open-source work is stored in git repositories, but our client work is still stored in Subversion repositories, and probably will be for some time. While git is amazing, Subversion still has its good qualities, and makes an excellent centralized repository, especially with its ecosystem of user-friendly tools.

The integration between git and Subversion (git-svn) is so well done that several of us have been using git as our interface to all our Subversion repositories. Doing this is fairly simple, but there are some interesting tricks, and so I thought I would share a day in the Viget life with git-svn.

Continue reading "Effectively Using Git With Subversion"

Installing Sphinx on OS X Leopard

Clinton R. Nixon
Clinton R. Nixon, Senior Developer, April 17, 2008 8

I am working on a project where we are using Ultrasphinx as the search solution for the site. I had to install Sphinx to make this work, and I soon found out that the version of Sphinx in MacPorts is one release too old to work with Ultrasphinx. (You need to use the latest release of version 0.9.8.) I very much like using package management, but sometimes you have to bite the bullet and compile something yourself.

When I tried to compile Sphinx with the tried-and-true ./configure; make; make install, I ran into some serious problems. It wouldn’t compile, and gave me this error:

g++  -Wall -g -D_FILE_OFFSET_BITS=64 -O3 -DNDEBUG   
-o indexer  indexer.o libsphinx.a  -L/opt/local/lib 
-L/opt/local/lib/mysql5/mysql -lmysqlclient -L/opt/local/lib 
-lz -lm  -L/opt/local/lib -lssl -lcrypto  -liconv -lexpat  
-L/usr/local/lib
Undefined symbols:
  "_iconv_close", referenced from:
      xmlUnknownEncoding(void*, char const*, XML_Encoding*)in libsphinx.a(sphinx.o)
  "_iconv", referenced from:
      xmlUnknownEncoding(void*, char const*, XML_Encoding*)in libsphinx.a(sphinx.o)
  "_iconv_open", referenced from:
      xmlUnknownEncoding(void*, char const*, XML_Encoding*)in libsphinx.a(sphinx.o)
ld: symbol(s) not found
collect2: ld returned 1 exit status
make[2]: *** [indexer] Error 1
make[1]: *** [all] Error 2
make: *** [all-recursive] Error 1

It turns out that I needed to compile the latest versions of the expat XML parser and iconv. Here’s a quick guide to how I got everything working:

Download iconv from the GNU project and compile it.

curl -O http://ftp.gnu.org/gnu/libiconv/libiconv-1.12.tar.gz
tar zxvf libiconv-1.12.tar.gz
cd libiconv-1.12
./configure --prefix=/usr/local
make
sudo make install
cd ..

I’m installing everything in /usr/local, and I suggest you do, too. I don’t want to mix up the programs I compile with the OS X system libraries and binaries (/usr) or MacPorts’ libraries and binaries (/opt/local).

Download expat and compile it.

curl -O http://internap.dl.sourceforge.net/sourceforge/expat/expat-2.0.1.tar.gz
tar zxvf expat-2.0.1.tar.gz
cd expat-2.0.1
./configure --prefix=/usr/local
make
sudo make install
cd ..

Download Sphinx and compile it. There’s a new flag given to configure this time, specifying the location of my MySQL installation. I installed it via MacPorts; if you installed it differently, you will have to change this flag. Also, you may want to go to the Sphinx download page to see if there’s a new version of Sphinx out. The version current while I’m writing this is a release candidate, and a finished release of 0.9.8 may be out by the time you read this.

curl -O http://www.sphinxsearch.com/downloads/sphinx-0.9.8-rc2.tar.gz
tar zxvf sphinx-0.9.8-rc2.tar.gz
cd sphinx-0.9.8-rc2
./configure --prefix=/usr/local --with-mysql=/opt/local/lib/mysql5
make
sudo make install
cd ..

The install is quick and easy, but certainly wasn’t when I was trying to figure out why Sphinx wouldn’t compile.


Git with remotes and SVN

Ben Scofield
Ben Scofield, Development Director, April 01, 2008 4

The laziness plugin I’ve been working on is hosted in two different SCM systems: Subversion, at Viget’s SVN repository, and git, at GitHub. I use git in development, which means that pushing out to GitHub is easy - but maintaining a git-svn connection at the same time is a little tricky.

Starting from this post, I finally got things moving. Basically, I created a local branch to interact with SVN independently of the main development; when new features (like the specific exception handling I added recently) are done, I push ‘em out to GitHub normally. Then I switch into the aforementioned local branch, merge from master, and dcommit them up.

The only problem I’ve run into is the occasional conflict on merging from master - and that’s easily resolvable by editing the conflicted file and git adding it before committing and dcommitting.

I long for the day when I can get by on git alone, but until then this appears to be a workable solution.

cURL and Your Rails 2 App

David Eisinger
David Eisinger, Web Developer, March 28, 2008 5

If you’re anything like me, you’ve used cURL to download a batch of MP3 files from the web, or to move a TAR file from one remote server to another. It might come as a surprise, then, that cURL is a full-featured HTTP client, which makes it perfect for interacting with RESTful web services like the ones encouraged by Rails 2. To illustrate, let’s create a small Rails app called ‘tv_show’:

rails tv_show
cd tv_show
script/generate scaffold character name:string action:string
rake db:migrate
script/server

Fire up your web browser and create a few characters. Once you’ve done that, open a new terminal window and try the following:

curl http://localhost:3000/characters.xml

You’ll get a nice XML representation of your characters:

<?xml version"1.0" encoding="UTF-8"?>
<characters type="array">
  <character>
    <id type="integer">1</id>
    <name>George Sr.</name>
    <action>goes to jail</action>
    <created-at type="datetime">2008-03-28T11:01:57-04:00</created-at>
    <updated-at type="datetime">2008-03-28T11:01:57-04:00</updated-at>
  </character>
  <character>
    <id type="integer">2</id>
    <name>Gob</name> 
    <action>rides a Segway</action>
    <created-at type="datetime">2008-03-28T11:02:07-04:00</created-at>
    <updated-at type="datetime">2008-03-28T11:02:12-04:00</updated-at>
  </character>
  <character>
    <id type="integer">3</id>
    <name>Tobias</name>
    <action>wears cutoffs</action>
    <created-at type="datetime">2008-03-28T11:02:20-04:00</created-at>
    <updated-at type="datetime">2008-03-28T11:02:20-04:00</updated-at>
  </character>
</characters>

You can retrieve the representation of a specific character by specifying his ID in the URL:

dce@roflcopter ~ > curl http://localhost:3000/characters/1.xml <?xml version="1.0" encoding="UTF-8"?> <character> <id type="integer">1</id> <name>George Sr.</name> <action>goes to jail</action> <created-at type="datetime">2008-03-28T11:01:57-04:00</created-at> <updated-at type="datetime">2008-03-28T11:01:57-04:00</updated-at> </character>

To create a new character, issue a POST request, use the -X flag to specify the action, and the -d flag to define the request body:

curl -X POST -d "character[name]=Lindsay&character[action]=does+nothing" http://localhost:3000/characters.xml

Here’s where things get interesting: unlike most web browsers, which only support GET and POST, cURL supports the complete set of HTTP actions. If we want to update one of our existing characters, we can issue a PUT request to the URL of that character’s representation, like so:

curl -X PUT -d "character[action]=works+at+clothing+store" http://localhost:3000/characters/4.xml

If we want to delete a character, issue a DELETE request:

curl -X DELETE http://localhost:3000/characters/1.xml

For some more sophisticated uses of REST and Rails, check out rest-client and ActiveResource.

Rails 2 and test/spec

Clinton R. Nixon
Clinton R. Nixon, Senior Developer, March 24, 2008 1

We’ve been flirting with behavior-driven development here at the Labs recently, and have tried out RSpec and test/spec. Both have advantages, but I like test/spec a little more: it works well with existing Test::Unit tests and has a syntax I find more natural.

Somewhere along the path to Rails 2, test/spec stopped working well for me. New test classes — ActiveSupport::TestCase, ActionController::TestCase, and ActionMailer::TestCase — were introduced to eliminate repeated code in Rails tests, and test/spec classes, which inherit from Test::Unit::TestCase, suddenly didn’t transparently work.

Working on a personal project this weekend, I decided to figure out how to use test/spec again. Digging through its code, I found this gem:

def context(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
  (Test::Spec::CONTEXTS[self.name + "\t" + name] ||= klass.new(name, self, superclass)).add(&block)
end

So now, if I want to use test/spec in my Rails tests, I just put the superclass after the context name, like so:

# For models
context "User", ActiveSupport::TestCase
  ...
end

# For controllers
context "User Controller", ActionController::TestCase
  ...
end

# For mailers
context "User Mailer", ActionMailer::TestCase
  ...
end

We're the Developers

at Viget Labs. We write about web development trends, tips, best practices, industry events, and our projects — all with an emphasis on Ruby on Rails.

Recent Comments

Tony,

I understand and agree that the back-end shouldn’t output code (html code), and only content. The templates (aka views) should do the trick, but instead of having lot’s of if/else conditionals inside the view, you may just output the following content.

No information available

The template would loop in an array and put all the <li>’s inside the <ul>.
I don’t see anything wrong, nor...