<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>the evolving ultrasaurus &#187; code</title>
	<atom:link href="http://www.ultrasaurus.com/sarahblog/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ultrasaurus.com</link>
	<description>Sarah Allen's reflections on internet software and other topics</description>
	<lastBuildDate>Sun, 21 Feb 2010 16:56:26 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>rails security review checklist</title>
		<link>http://www.ultrasaurus.com/sarahblog/2010/01/rails-security-review-checklist/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2010/01/rails-security-review-checklist/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 08:00:12 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=2378</guid>
		<description><![CDATA[I&#8217;m reviewing the security of a web app built with Ruby on Rails, so I put together a checklist for a security audit.  This isn&#8217;t a bank or high security situation, but there were a number of engineers and quite a bit of open source code, so I thought a few checks were in [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m reviewing the security of a web app built with Ruby on Rails, so I put together a checklist for a security audit.  This isn&#8217;t a bank or high security situation, but there were a number of engineers and quite a bit of open source code, so I thought a few checks were in order.</p>
<p>Here&#8217;s the list I came up with that I thought other folks might appreciate as a starting point (special thanks to the sfruby list, <a href="http://afreshcup.com/">Mike Gunderloy</a>, and Scott Bronson for feedback):</p>
<p>0) Make sure your Rails and gems are up to date for latest security patches (see <a href="http://groups.google.com/group/rubyonrails-security">rails security mailing list</a> for recent advisory notes)</p>
<p>1) Active Record audit:<br />
&nbsp;&nbsp;A) SQL injection:<br />
&nbsp;&nbsp;&nbsp;&nbsp;(i) whole word search for &#8220;find&#8221;, &#8220;first&#8221;, and &#8220;all&#8221; then visually inspect all instances of ActiveRecord find calls for potential SQL injection vulnerability (also search for &#8220;sql&#8221; not whole work search to find find_by_sql and &#8220;execute&#8221; to find cases where raw sql is executed.<br />
&nbsp;&nbsp;&nbsp;&nbsp;(ii) search your models for &#8220;named_scope&#8221; and check :conditions<br />
&nbsp;&nbsp;B) check for <a href="http://railspikes.com/2008/9/22/is-your-rails-application-safe-from-mass-assignment">mass assignment</a>  Either disable mass assignment as Eric suggests in his article, or audit its use.  If doing an audit, check every model to make sure it declares which attributes are settable with attr_accessible.  (While attr_protected may technically work, a white list approach is recommended by security experts and the <a href="http://groups.google.com/group/rubyonrails-security/browse_thread/thread/42c4d5d3b7354735">rails security advisory</a> on this topic)</p>
<p>2) Scripting attack: search all eRB files for &lt;%= and ensure that if dynamically generated text was originally entered by the user, it is HTML escaped. Consider <a href="http://github.com/nzkoz/rails_xss">rails_xss</a></p>
<p>3) Secure Access: If some of the site does not have public access, check controllers and ensure that public actions are specifically allowed and that protected access is the default</p>
<p>4) search for &#8220;eval&#8221; (whole word) and verify that  usages are safe (assume javascript eval is ok)</p>
<p>5) search for &#8220;forgery&#8221; (not whole word), make sure that<br />
config.action_controller.allow_forgery_protection    = false<br />
is only disabled in test config<br />
 protect_from_forgery should be in the ApplicationController, unless there is a good reason for it not to be</p>
<p>6) check user auth and review that controller actions are limited to expected use</p>
<p>7) passwords: not saved as clear-text in the db, not logged</p>
<p>8) check that private data is not stored in cookies </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2010/01/rails-security-review-checklist/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>markdown to textile with vim regex</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/12/markdown-to-textile-with-vim-regex/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/12/markdown-to-textile-with-vim-regex/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 08:36:20 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=2331</guid>
		<description><![CDATA[So, I needed to change markdown to textile and google didn&#8217;t yield any handy scripts, so I sharpened my vim fu with Rubular, my favorite regular expression tester and came up with a few substitutions that took care of everything but lists and code blocks.
In vi, type ESC to go into command mode, then :%s/one/two/g [...]]]></description>
			<content:encoded><![CDATA[<p>So, I needed to change markdown to textile and google didn&#8217;t yield any handy scripts, so I sharpened my vim fu with <a href="http://www.rubular.com/">Rubular</a>, my favorite regular expression tester and came up with a few substitutions that took care of everything but lists and code blocks.</p>
<p>In vi, type ESC to go into command mode, then :%s/one/two/g will find every instance of &#8220;one&#8221; and replace it with &#8220;two&#8221;</p>
<p>First the easy stuff, headers.  ^ finds the beginning of the line.</p>
<pre>
:%s/^# /h1. /g
:%s/^## /h2. /g
:%s/^### /h3. /g
</pre>
<p>To replace images, I needed to replace ![alt-text](link) with !link! so I needed to capture text.  I suppose I didn&#8217;t really need the first capture, but I was working on the replace expression for a regular link when I realized it would be easier to do the images first.  To understand the expression below, you need to know that \(stuff\) captures some text which can be inserted in the replacement text with \1 and \2, etc.  So to get everything between square brackets, I use [\(.*\)] </p>
<pre>
:%s/!\[\(.*\)](\(.*\))/!\2!/g
</pre>
<p>All of my images appeared on a single line, so I didn&#8217;t catch a potential issue in the above expression until I got to replacing text links.  I needed to use a non &#8220;greedy&#8221; capture so that I wouldn&#8217;t pull in text after the link that happened to include a parenthetical comment.  Normally, in reg ex I would use (.*?) but in vim I needed to write \(.\{-}\) &#8230;wtf?</p>
<pre>
:%s/\[\(.*\)](\(.\{-}\))/"\1":\2/g
</pre>
<p>Special thanks to Adam Wolf&#8217;s tip via <a href="http://www.sharegrove.com">ShareGrove</a> which helped me document these steps.</p>
<blockquote><p>you can put VIM in a mode where the <a href="http://vimdoc.sourceforge.net/htmldoc/cmdline.html#Command-line">command history</a> is just like another buffer. Not in insert mode, try q: </p></blockquote>
<blockquote><p>You should get a new buffer that you can edit with the command history in it, so &#8220;*yy would yank the current line into the system clipboard, etc.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/12/markdown-to-textile-with-vim-regex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>creating a custom rake task</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/12/creating-a-custom-rake-task/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/12/creating-a-custom-rake-task/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 17:30:51 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=2236</guid>
		<description><![CDATA[There&#8217;s a nice Railscast introduction to rake for Rails, which goes into a number of other important details that aren&#8217;t covered in this post.  Below is a little tutorial of creating a Rails rake task and getting it to run remotely on heroku.
Introduction to Rake
In lib/tasks, create a file called greet.rake

task :greet do
  [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a nice <a href="http://railscasts.com/episodes/66-custom-rake-tasks">Railscast introduction to rake</a> for Rails, which goes into a number of other important details that aren&#8217;t covered in this post.  Below is a little tutorial of creating a Rails rake task and getting it to run remotely on heroku.</p>
<h2>Introduction to Rake</h2>
<p>In lib/tasks, create a file called greet.rake</p>
<pre>
task :greet do
   puts "Hello world"
end
</pre>
<p>By naming the task .rake and putting it in this special place rails will automatically pick it up and make it available to you.  You can see it listed if you type: rake -T on the command line.  To run it:</p>
<pre>
rake greet
</pre>
<p>which will print &#8220;Hello world&#8221;</p>
<p>to run one task before another, specify a dependency like this (multiple tasks may be specified in the same file):</p>
<pre>
task :ask => :greet do
   puts "How are you?"
end
</pre>
<h2>Writing a Practical Rake Task</h2>
<p>Now for the task at hand, I&#8217;m going to create a rake task which creates a bunch of fake data for me to test with.  First I&#8217;ll create a little experimental app:</p>
<pre>
rails rake_example
cd rake example
script/generate scaffold person first_name:string last_name:string
rake db:migrate
</pre>
<p>Here&#8217;s the rake task (lib/tasks/fake_people.rake):</p>
<pre>
require 'faker'

namespace :admin  do
  desc "create some fake data"
  task :fake_people => :environment do
    print "How many fake people do you want?"
    num_people = $stdin.gets.to_i
    num_people.times do
      Person.create(:first_name => Faker::Name.first_name,
                    :last_name => Faker::Name.last_name)
    end
    print "#{num_people} created.\n"
  end
end
</pre>
<p>Note that I&#8217;m using the faker gem (<a href="http://faker.rubyforge.org/rdoc/">docs here</a>) and I created a task dependency on loading the rails environment so I could access my Person model.</p>
<p>Now I can run</p>
<pre>
rake admin:fake_people
</pre>
<p>and it will prompt me to ask how many I want and then it will create them.  Cool goodness, yes?</p>
<h2>Running Remotely on Heroku</h2>
<p>We&#8217;re not done yet.  I want to deploy this on heroku and be able to run the task remotely.  For this, there are two gotchas, first I can&#8217;t run an interactive script remotely; also I need to tell heroku that I am using the fake gem and make sure it is installed.</p>
<h3>1) removing interactivity</h3>
<p>Instead of an interactive script, we can set an environment variable or command line argument (thanks to a <a href="http://groups.google.com/group/heroku/browse_thread/thread/775f445e5b11e498/">tip by Adam Wiggins</a>).  </p>
<p>My modified task looks like this:</p>
<pre>
require 'faker'

namespace :admin  do
  desc "create some fake data"
  task :fake_people => :environment do
    num_people = ENV['NUM_RECORDS'].to_i
    num_people.times do
      Person.create(:first_name => Faker::Name.first_name,
                    :last_name => Faker::Name.last_name)
    end
    print "#{num_people} created.\n"
  end
end
</pre>
<p>which I can call locally from the command line like this:</p>
<pre>
rake admin:fake_people NUM_RECORDS=1
</pre>
<h3>2) adding gem to heroku</h3>
<p>I need to create a <a href="http://blog.heroku.com/archives/2009/3/10/gem_manifests/">gems manifest</a>, which sounds fancy, but is simply creating a .gems file at the root of my app with contents similar to what I would put in my config environment.rb to specify that my app requires a gem:</p>
<pre>
faker --version ">=0.3.1"
</pre>
<h3>3) Deploy and Run</h3>
<p>So I can deploy my app to heroku with the usual steps</p>
<pre>
git init
git add .
git commit -m "example app for rake script testing"
heroku create
git push heroku master
heroku rake db:migrate
</pre>
<p>and run the task remotely:</p>
<pre>
heroku rake admin:fake_people NUM_RECORDS=1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/12/creating-a-custom-rake-task/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>rails exceptions in xml</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/09/rails-exceptions-in-xml/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/09/rails-exceptions-in-xml/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 18:13:57 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=2058</guid>
		<description><![CDATA[We ran into an issue last week where our XML APIs were returning HTML under certain error conditions, rather than the expected XML.  Our solution was to add the following code to the ApplicationController:

  rescue_from Exception do &#124;exception&#124;
    respond_to do &#124;format&#124;
      format.xml  { render [...]]]></description>
			<content:encoded><![CDATA[<p>We ran into an issue last week where our XML APIs were returning HTML under certain error conditions, rather than the expected XML.  Our solution was to add the following code to the ApplicationController:</p>
<pre>
  rescue_from Exception do |exception|
    respond_to do |format|
      format.xml  { render :xml =&gt;
           "&lt;error&gt;Internal Server Error #{exception.message}&lt;/error&gt;",
           :status => 500 }
      format.html { render :html =&gt; {:file =&gt; 'public/500.html'}, :status =&gt; 500 }
      format.json { render :json =&gt;
            {:error =&gt; "Internal Server Error #{exception.message}"}.to_json,
             :status => 500 }
    end
  end
</pre>
<p>We might have also declared a rescue_action, and I&#8217;m not sure of the benefits of one over the other, except that perhaps we needed to implement a general form of rescue_from since we had another more specific form already declared.</p>
<p>It seemed to me that this should be the default behavior in rails, so I decided to dig into it a little more and see what I could discover.  I started by making a little test app to reproduce the exception.  The particular case from last week was a database limit that wasn&#8217;t being caught in the app with a length validation.  When I tried to re-create the error in MySql, I noticed that no exception is thrown since MySql will just truncate the data (although perhaps that is only because I am not running MySql in strict mode).  In PostgreSQL, the database layer will throw an exception.</p>
<p>Test app setup:</p>
<pre>
rails -d postgresql test_postgresql
cd test_postgresql/
script/generate scaffold person first:string last:string present:boolean
</pre>
<p>Edit the migration to create a database limit:</p>
<pre>
class CreatePeople &lt; ActiveRecord::Migration
  def self.up
    create_table :people do |t|
      t.string :first, :limit => 40
      t.string :last, :limit => 40
      t.boolean :present

      t.timestamps
    end
  end

  def self.down
    drop_table :people
  end
end
</pre>
<p>Create the postgres user.  Note double-quotes around user, single quotes around password. It has to be that way.  Go figure.</p>
<pre>
$ sudo su postgres -c psql
postgres=# create user "test_postgresql" with superuser password 'password';
CREATE ROLE
postgres=# \q
</pre>
<p>Finally create the database, run migration, and start the server:</p>
<pre>
rake db:create:all
rake db:migrate
./script/server
</pre>
<p>If you point your browser at http://localhost:3000/people and try to create a person with more that 40 characters in the first name, you will see the following error:</p>
<pre>
ActiveRecord::StatementInvalid in PeopleController#create
PGError: ERROR:  value too long for type character varying(40)
</pre>
<p>That is all well and good; however, if you do the same in XML, you will get the same error in <strong>HTML</strong>.</p>
<pre width="80">
$ curl -X POST -d &quot;&lt;person&gt;&lt;first&gt;This is a first name that is too long for the database limit&lt;/first&gt;&lt;/person&gt;&quot; -H &quot;Content-Type: application/xml&quot; http://localhost:3000/people.xml
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
  &lt;title&gt;Action Controller: Exception caught&lt;/title&gt;
  &lt;style&gt;
    body { background-color: #fff; color: #333; }

    body, p, ol, ul, td {
      font-family: verdana, arial, helvetica, sans-serif;
      font-size:   13px;
      line-height: 18px;
    }
</pre>
<p>That seems like a bug to me.  Perhaps this should be a lighthouse ticket rather than a blog post.. still not confident in identifying bugs in Rails, so I figured I&#8217;d post here first.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/09/rails-exceptions-in-xml/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>rails models are views?</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/08/rails-models-are-views/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/08/rails-models-are-views/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 03:07:10 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=2032</guid>
		<description><![CDATA[Rails appears pretty strict about separation of the abstraction layers that make up its notion of a web application: models, view and controllers.  If you were to suggest calling a presentation method, such as url_for, in your model, the stoic Rails advocate will have an allergic reaction. However, Rails thinks nothing of rendering a [...]]]></description>
			<content:encoded><![CDATA[<p>Rails appears pretty strict about separation of the abstraction layers that make up its notion of a web application: models, view and controllers.  If you were to suggest calling a presentation method, such as url_for, in your model, the stoic Rails advocate will have an allergic reaction. However, Rails thinks nothing of rendering a model directly as a view, such as:</p>
<pre>
format.json { render :json => @products }
</pre>
<p>Now, one might argue that this is controller code and the controller is allowed to interpret the model as a view.  The controller&#8217;s job is to mediate this interaction.  However, I feel that it is a dangerous shortcut, made even more so by how hard to seems to be to override.  Perhaps the json implementation is simply incomplete.</p>
<p>In xml, this strange controller pattern is easily corrected by <a href="http://danengle.us/2009/05/generating-custom-xml-for-your-rails-app/">providing an xml view</a>.  The xml builder syntax is particularly readable, and it is easy to design your XML API effectively.</p>
<p>I haven&#8217;t found an equivalent for json.  I tried to use a JSON API today to no avail.  My model included image data which breaks when auto-rendered in JSON.  What I really wanted was to include a URL instead of the image data, which I implement neatly in my xml.builder view:</p>
<pre>
xml.instruct!
xml.products("type"=>"array") do
  @products.each do |product|
    xml.product do
      xml.sku product.sku
      xml.name product.name
      xml.brand product.brand
      xml.img_url url_for(:controller => :products, :action => :show, :format=>:png, :id => product.id, :only_path => false)
    end
  end
end
</pre>
<p>The problem is that I want a similar view in JSON.  The to_json API leads me to put this logic in my model (gasp!).  In fact, the ActiveRecord::Serialization docs give an example of providing a method to generate JSON instead of a literal attribute.  The example is of a &#8220;permalink&#8221; which seem suspiciously like something that belongs is the view layer.</p>
<pre>
  konata.to_json(:methods => :permalink)
  # => {"id": 1, "name": "Konata Izumi", "age": 16,
        "created_at": "2006/08/01", "awesome": true,
        "permalink": "1-konata-izumi"}
</pre>
<p>Today&#8217;s solution was to go back to using my comfortable old XML API, but I would prefer to consume JSON from the other side.  I wonder if anyone is working on a JSON builder or if there is some clear solution that I haven&#8217;t yet stumbled upon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/08/rails-models-are-views/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ruby unit test frameworks</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/08/ruby-unit-test-frameworks/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/08/ruby-unit-test-frameworks/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 14:59:46 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=1997</guid>
		<description><![CDATA[In preparation for teaching Ruby in a class with test first teaching.  I decided to evaluate a few test frameworks.  I thought initially to use Test::Unit, since it seemed easy to understand and ships with Rails.  Wolfram Arnold argued that Test::Unit would burden the new folks with legacy.  Alex Chaffee also [...]]]></description>
			<content:encoded><![CDATA[<p>In preparation for teaching Ruby in a class with <a href="http://www.ultrasaurus.com/sarahblog/2009/08/test-driven-teaching/">test first teaching</a>.  I decided to evaluate a few test frameworks.  I thought initially to use Test::Unit, since it seemed easy to understand and ships with Rails.  Wolfram Arnold argued that Test::Unit would <a href="http://twitter.com/wolframarnold/status/3336210949">burden the new folks with legacy</a>.  Alex Chaffee also <a href="http://twitter.com/alexch/status/3320591021">advocated RSpec</a>, but <a href="http://twitter.com/jacobrothstein/status/3320555832">other</a> <a href="http://twitter.com/jamieflournoy/status/3323143202">friends</a> from the Twittervese had good things to say about shoulda.  Some folks declared it to be simply a <a href="http://twitter.com/noelrap/status/3319780641">matter of taste</a>.</p>
<p>Even so, I wanted to make an informed decision and refine my palette for Ruby tools, so I wrote a simple exercise in each of Test::Unit, Shoulda and RSpec.</p>
<h2>Test::Unit</h2>
<pre>
require 'test/unit'
require 'pig_latin'

class PigLatinTest < Test::Unit::TestCase
    include PigLatinTranslator

    def test_simple_word
        s = translate("nix")
        assert_equal("ixnay", s)
    end

    def test_word_beginning_with_vowel
        s = translate("apple")
        assert_equal("appleay", s)
    end

    def test_two_consonant_word
        s = translate("stupid")
        assert_equal("upidstay", s)
    end
end
</pre>
<p>With the above code saved as "test_pig_latin.rb" you run it by simply executing it with Ruby.</p>
<pre>$ ruby test_pig_latin.rb
Loaded suite test_pig_latin
Started
FFF
Finished in 0.01091 seconds.

  1) Failure:
test_simple_word(PigLatinTest) [test_pig_latin.rb:9]:
<"ixnay"> expected but was
<"translation">.

  2) Failure:
test_two_consonant_word(PigLatinTest) [test_pig_latin.rb:19]:
<"upidstay"> expected but was
<"translation">.

  3) Failure:
test_word_beginning_with_vowel(PigLatinTest) [test_pig_latin.rb:14]:
<"appleay"> expected but was
<"translation">.

3 tests, 3 assertions, 3 failures, 0 errors
</pre>
<hr />
<h2>Shoulda</h2>
<p>Notice in the code below that Shoulda is simply and extension to Test::Unit.  The PigLatinTest also subclasses Test::Unit::TestCase, just as the example above; however, the code inside the test case looks substantially different (and more readable in my opinion).  You can actually mix Shoulda tests (below) with regular TestCase test methods (above) in the same TestCase.  This is an advantage to Shoulda over RSpec if you have a codebase that already has lots of unit tests; however, I have also used RSpec and Test::Unit in the same project (you just have to remember to 'rake test' and 'rake spec').</p>
<pre>require 'rubygems'
require 'shoulda'
require 'pig_latin'

class PigLatinTest &lt; Test::Unit::TestCase
  include PigLatinTranslator

  context "#translate" do

    should "translate a simple word: nix" do
      s = translate("nix")
      assert_equal("ixnay", s)
    end

    should "translate a word beginning with a vowel: apple" do
      s = translate("apple")
      assert_equal("appleay", s)
    end

    should "translate a two consonent word: stupid" do
      s = translate("stupid")
      assert_equal("upidstay", s)
    end

  end
end</pre>
<p>With the code above saved as "test_shoulda_pig_latin.rb" you use the same process as above by just executing the file with ruby.</p>
<pre>$ ruby test_shoulda_pig_latin.rb
Loaded suite test_shoulda_pig_latin
Started
FFF
Finished in 0.008268 seconds.

 1) Failure:
test: #translate should translate a simple word. (PigLatinTest)
 [test_shoulda_pig_latin.rb:12:in `__bind_1251676444_52936'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `call'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `test: #translate should translate a simple word. ']:
&lt;"ixnay"&gt; expected but was
&lt;"translation"&gt;.

 2) Failure:
test: #translate should translate a two consonent word. (PigLatinTest)
 [test_shoulda_pig_latin.rb:22:in `__bind_1251676444_58860'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `call'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `test: #translate should translate a two consonent word. ']:
&lt;"upidstay"&gt; expected but was
&lt;"translation"&gt;.

 3) Failure:
test: #translate should translate a word beginning with a vowel. (PigLatinTest)
 [test_shoulda_pig_latin.rb:17:in `__bind_1251676444_59935'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `call'
 /Library/Ruby/Gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:351:in `test: #translate should translate a word beginning with a vowel. ']:
&lt;"appleay"&gt; expected but was
&lt;"translation"&gt;.

3 tests, 3 assertions, 3 failures, 0 errors</pre>
<hr />
<h2>RSpec</h2>
<pre>require "pig_latin"

describe "#translate" do
  include PigLatinTranslator

  it "should translate a simple word" do
    s = translate("nix")
    s.should == "ixnay"
  end

  it "should translate a word beginning with a vowel" do
    pending
    s = translate("apple")
    s.should == "appleay"
  end

  it "should translate a two consonent word: stupid" do
    pending
    s = translate("stupid")
    s.should == "upidstay"
  end

end</pre>
<p>The code above is saved in a file called "pig_latin_spec.rb" and run it using the 'spec' command.  You will need to have installed the rspec gem (sudo gem install rspec).</p>
<pre>$ spec pig_latin_spec.rb
F**

Pending:

#translate should translate a word beginning with a vowel (TODO)
./pig_latin_spec.rb:11

#translate should translate a two consonent word: stupid (TODO)
./pig_latin_spec.rb:17

1)
'#translate should translate a simple word' FAILED
expected: "ixnay",
     got: "translation" (using ==)
./pig_latin_spec.rb:8:

Finished in 0.035728 seconds

3 examples, 1 failure, 2 pending</pre>
<h2>Conclusion</h2>
<p>I like RSpec best since I find the output to be most readable.  I love the pending keyword, which allows me to set up the tests as an exercise for the class with only one test failing. I find it helps focus on exactly one test and one failure.   I considered going with Shoulda because the tests are just as readable as RSpec, even if the output takes some learning to read, because of my initial thought that Test::Unit held less magic.  However, on closer inspection, I realized that Test::Unit has one significant magical incantation:  you merely declare a class and when that class is defined, it runs the test.  This seemed not the kind of topic I would want to teach in an intro class.  Even some experienced programmers might struggle with understanding the mechanism that allows such a construct to function.  I concluded that all of the test frameworks require serious magic, and picked RSpec since I found it to be most usable for test writing and analysis of the output.</p>
<p>Caveat: this exercise was for pure Ruby.  In Rails, I wonder if Shoulda tests would be more concise, making them easier to write and read and, therefore, making it worth the steeper learning curve on reading the output.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/08/ruby-unit-test-frameworks/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>rails admin interface roundup</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/07/rails-admin-interface-roundup/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/07/rails-admin-interface-roundup/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 15:23:32 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=1651</guid>
		<description><![CDATA[After my recent ActiveScaffold post, I heard about several newer alternatives from Jaime Flournoy, Mike Gunderloy, and some more web surfing.  I evaluated four plugins for admin UI, using the following methodology: 

rails xxx_simple
cd xxx_simple/
./script/generate scaffold Task title:string notes:text  complete:boolean
rake db:migrate
 
plus whatever annotations to the code the plugin needed.  Then I [...]]]></description>
			<content:encoded><![CDATA[<p>After my recent <a href="http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/">ActiveScaffold post</a>, I heard about several newer alternatives from <a href="http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/#comment-781">Jaime Flournoy</a>, <a href="http://twitter.com/MikeG1/status/2442160429">Mike Gunderloy</a>, and some more <a href="http://ruby-toolbox.com/categories/rails_admin_interfaces.html">web surfing</a>.  I evaluated four plugins for admin UI, using the following methodology: </p>
<p><code><br />
rails xxx_simple<br />
cd xxx_simple/<br />
./script/generate scaffold Task title:string notes:text  complete:boolean<br />
rake db:migrate<br />
</code> </p>
<p>plus whatever annotations to the code the plugin needed.  Then I ran a little script to generate 500 records:</p>
<p><code> 500.times do |counter|<br />
&nbsp;&nbsp;`curl -X POST -d "Another thing #{counter}More text with #{counter} thing" -H "Content-Type: application/xml" http://localhost:3000/tasks.xml`<br />
end<br />
</code><br />
They all support related models, but I only have screen shots from my simple test.  I&#8217;ve listed them below with the ones I liked best at the top.  </p>
<h2>typus</h2>
<p><a href="http://github.com/fesplugas/typus/tree/master  ">Typus</a> is the one I&#8217;m moving forward with. It has a clean interface and has nice configuration options. You can configure which columns are displayed and which are searched (with a nice UI touch of displaying the search criteria under the search box).  It is actively maintained with quite a few contributors and a responsive <a href="http://groups.google.com/group/typus">google group</a>.  I really like how relationships are displayed (for which I don&#8217;t have a picture, sorry).  The only drawback (for me) is that it has its own auth and I don&#8217;t really want to introduce a separate set of admin users for the project I am working on, and I&#8217;ll be looking into making a change to support my own auth.  By default, it adds it&#8217;s own typus_users table, but this could be a plus for some.</p>
<p><code><br />
script/plugin install git://github.com/fesplugas/typus.git<br />
script/generate typus<br />
rake db:migrate<br />
./script/server<br />
<code></p>
<p>Now visit http://localhost:3000/admin and you will be prompted for your email address, from which it will automatically create the first admin user (pretty slick).  The default UI looks like this:</p>
<p><img src="http://img.skitch.com/20090705-fkut2mh3se18h2acxbfh1msgg4.jpg" /><br />
<img src="http://img.skitch.com/20090705-qxnawftfwf9na6m4eacejxy41h.jpg" /> I ran into just one glitch where Rails reported "A copy of ApplicationController has been removed from the module tree but is still active!" but it was <a href="http://groups.google.com/group/typus/browse_thread/thread/70fba777518e26e">easily fixed</a>.  The error didn't happen in my simple project, but did in my real app.  Francesc Esplugas has looked into it and so far <a href="http://groups.google.es/group/typus/msg/051eff4f5089c5f9?hl=en">can't reproduce it</a>.</p>
<h2>admin_data</h2>
<p>I really liked <a href="http://github.com/neerajdotname/admin_data/tree/master">admin_data</a>.  The simplicity of the install was breath-taking:<br />
<code><br />
ruby script/plugin install git://github.com/neerajdotname/admin_data.git<br />
sudo gem install will_paginate<br />
./script/server<br />
</code></p>
<p>that's it. Now visit http://localhost:3000/admin_data and you'll see the following interface:</p>
<p><img src="http://img.skitch.com/20090705-gs9rwj23bdn6au6d9ahekca3te.jpg" /><br />
<img src="http://img.skitch.com/20090705-cj86eyr95cjnbw1gn7k1b3taq8.jpg" /></p>
<p>I didn't try it, but I really like the admin_data approach to integrating with the application's authentication:  Add the following lines of code in an initializer at ~/config/initializers/admin_data.rb</p>
<p><code><br />
# authorization check to see if the data should be shown to the user<br />
ADMIN_DATA_VIEW_AUTHORIZATION = Proc.new { |controller|<br />
&nbsp;&nbsp; controller.send("admin_logged_in?") }<br />
# authorization check to see if the user should be allowed to update the data<br />
ADMIN_DATA_UPDATE_AUTHORIZATION    = Proc.new { |controller| return false }<br />
</code></p>
<h2>streamlined</h2>
<p><a href="http://streamlinedframework.org/">Streamlined</a> is nice, but not as pretty as ActiveScaffold.  Not compatible with Rails 2.3.  This and active_scaffold seem to be a little older than typus and admin_data and require you to modify your code similarly.  I thought it nice that it provided its own admin layout.   In my simple test I applied the series of steps and nested route as with <a href="ttp://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/">active_scaffold</a>.<br />
<code><br />
  class MyNiftyController < ApplicationController<br />
&nbsp;&nbsp;layout 'streamlined'<br />
&nbsp;&nbsp;acts_as_streamlined</p>
<p>    ...[anything else you want to do]<br />
  end<br />
</code><br />
<img src="http://img.skitch.com/20090702-n3wgfmeh4wiq1k7bhfpj3fw79a.jpg" /><br />
<img src="http://img.skitch.com/20090702-q77sif7axcu6f15ardfiy7panx.jpg" /></p>
<h2>active_scaffold</h2>
<p>See my <a href="http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/">previous post</a> for details.  This seems to be the grand-daddy of this genre of plugins and has a very active <a href="http://groups.google.com/group/activescaffold">google group</a>.  I liked this plugin when I first tried it, but it hung when I applied it to my real app.  Also, <a href="http://twitter.com/jamieflournoy/status/2445545932">@jamieflournoy notes</a> that he didn't like the UI for editing related models as much as he did Streamlined.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/07/rails-admin-interface-roundup/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>getting started with activescaffold</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 06:32:09 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=1621</guid>
		<description><![CDATA[The ActiveScafold plugin for Rails promises to be a huge time saver.  In just a few easy steps, you can create a full web interface for your database, complete with inline editing and fold out panels.  Of course, it helps to have some grasp about what it is doing or you can get stuck like [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://activescaffold.com/">ActiveScafold</a> plugin for Rails promises to be a huge time saver.  In just a few easy steps, you can create a full web interface for your database, complete with inline editing and fold out panels.  Of course, it helps to have some grasp about what it is doing or you can get <a href="http://groups.google.com/group/activescaffold/browse_thread/thread/bb541afdf9acda3">stuck like I did</a> this morning.  I&#8217;m no expert (yet), but since it is so very cool, I wanted to share what I&#8217;ve learned (with the help of Sean Dick and Ivan Storck at tonight&#8217;s SFRuby Hack session).  </p>
<p>After installing the plugin, there are just 3 lines of code that magically generate the HTML pages, but the trick is knowing where to put them.  There&#8217;s a <a href="http://wiki.github.com/activescaffold/active_scaffold/how-to-approach-active-scaffold-use-cases-benefits">nice intro</a> on the github wiki that outlines common use cases:</p>
<ul>
<li> Prototyping</li>
<li>Admin Interfaces</li>
<li>Embedded, Widget-Style</li>
<li>Data-Heavy Applications</li>
</ul>
<p>The use case that led me to ActiveScaffold today was the creation of an admin interface.  I&#8217;m working on a website and the end user stuff is pretty nice, but there are a bunch of tables where the data needs a little love&#8230; no one wants to launch the site without at least a few corrections in the data and it is crazy to either delay the launch while we build an admin interface or have an engineer make corrections with sql updates.  Enter ActiveScaffold: a way to allow admins to make the changes they need with very little software development.  (Later I expect we&#8217;ll need to add some fancy bits to the admin interface, but ActiveScaffold promises to be configurable and extensible enough when the time comes and the key point is that I don&#8217;t expect to need those features this week.)</p>
<h2>ActiveScaffold for Admin</h2>
<p>Make a little app for this experiment:<br />
<code><br />
rails active_scaffold<br />
cd active_scaffold<br />
./script/generate scaffold Task title:string notes:text  complete:boolean<br />
rake db:migrate<br />
</code><br />
Install the plugin, which is compatible with Rails 2.3.2 (yay!) and previous versions of rails (if you <a href="http://wiki.github.com/activescaffold/active_scaffold/getting-started">install  a specific revision</a>)<br />
<code><br />
./script/plugin install git://github.com/activescaffold/active_scaffold.git<br />
</code><br />
Now we have an app that lets you create, view, edit and delete tasks.  This is the end-user app, you could edit the views and remove controller actions to prevent editing, deleting and/or creation.  We want to leave this interface as is, but create a separate set of pages to allow an administrator to view, create, modify and delete tasks.</p>
<p>Sean came up with the idea of using routes with a namespace to facilitate this.  Here&#8217;s what we came up with:</p>
<p>In config/routes.rb add the following code:<br />
<code><br />
  map.namespace :admin do |admin|<br />
&nbsp;&nbsp;&nbsp;admin.resources :tasks<br />
  end<br />
</code></p>
<p>Create a copy of /app/views/layouts/tasks.html.erb and call it admin.html.erb (in same folder), then add the following lines inside the &lt;head&gt; tag:<br />
<code><br />
  <%= javascript_include_tag :defaults %><br />
  <%= active_scaffold_includes %><br />
</code></p>
<p>Create app/controllers/task_controller.rb:<br />
<code><br />
class Admin::TasksController < TasksController<br />
&nbsp;&nbsp;&nbsp;layout "admin"<br />
&nbsp;&nbsp;&nbsp;active_scaffold :task<br />
end<br />
</code></p>
<p>Check it out:<br />
<code><br />
http://localhost:3000/admin/tasks<br />
</code><br />
<img src="http://img.skitch.com/20090702-tgy9a9y5g981xf589k6b3txjym.jpg"/><br />
and when you click edit:<br />
<img src="http://img.skitch.com/20090702-mm8tr6jceckp7y78kbc495nwnq.jpg"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/07/getting-started-with-activescaffold/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>openlaszlo simple post code</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/06/openlaszlo-simple-post-code/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/06/openlaszlo-simple-post-code/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 05:43:00 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=1584</guid>
		<description><![CDATA[Here&#8217;s a little form for sending an XML post in OpenLaszlo.  This is a useful little snippet of code, since as if you get one little content header or something wrong, Rails will be unforgiving with its powerful, yet strict implementation of REST.
What the app looks like (enter text in the top, click the [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little form for sending an XML post in OpenLaszlo.  This is a useful little snippet of code, since as if you get one little content header or something wrong, Rails will be unforgiving with its powerful, yet strict implementation of REST.</p>
<p>What the app looks like (enter text in the top, click the button, response is printed in the lower box):</p>
<p><img src="http://img.skitch.com/20090622-gts2h4rbw2pq7uwnpdq5e6ea2p.jpg"/></p>
<style type="text/css">
blockquote.code {
  font-style: normal;
  font-family: Monaco,monospace;
  font-size: 10px;
  border: solid 1px #aaa;
  padding: 6px;
  background-color: #eee;
  color: inherit;
  overflow:auto;
  margin: 10px 0px;
}
</style>
<p>The code:</p>
<blockquote class="code"><p>
&lt;canvas title=&quot;Test Post&quot; proxied=&quot;false&quot;&gt;<br />
&nbsp;&nbsp;&lt;dataset src=&quot;http:/projects.xml&quot; name=&quot;ds&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ondata=&quot;response.setAttribute(&#39;text&#39;this.childNodes[0].serialize())&quot;/&gt;<br />
&nbsp;&nbsp;&lt;simplelayout spacing=&quot;4&quot;/&gt;<br />
&nbsp;&nbsp;&lt;edittext id=&quot;postdata&quot; multiline=&quot;true&quot; width=&quot;400&quot; height=&quot;200&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp; text=&#39;&amp;lt;project&amp;gt;  &amp;lt;title&amp;gt;XXX&amp;lt;/title&amp;gt;  &amp;lt;/project&amp;gt;&#39;/&gt;<br />
&nbsp;&nbsp;&lt;button text=&quot;post&quot;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;handler name=&quot;onclick&quot;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ds.setQueryParam(&quot;lzpostbody&quot;, postdata.text);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ds.setAttribute(&quot;querytype&quot;, &quot;POST&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ds.setHeader(&quot;Content-Type&quot;, &quot;application/xml&quot;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ds.doRequest();<br />
&nbsp;&nbsp;&lt;/handler&gt;<br />
&nbsp;&nbsp;&lt;/button&gt;<br />
&nbsp;&nbsp;&lt;edittext id=&quot;response&quot;  multiline=&quot;true&quot; width=&quot;400&quot; height=&quot;280&quot;/&gt;<br />
&lt;/canvas&gt;
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/06/openlaszlo-simple-post-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>simple web services with rails</title>
		<link>http://www.ultrasaurus.com/sarahblog/2009/06/simple-web-services-with-rails/</link>
		<comments>http://www.ultrasaurus.com/sarahblog/2009/06/simple-web-services-with-rails/#comments</comments>
		<pubDate>Sun, 21 Jun 2009 18:05:23 +0000</pubDate>
		<dc:creator>Sarah</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://www.ultrasaurus.com/?p=1533</guid>
		<description><![CDATA[Rails enables web services by default, which is pretty awesome, and I&#8217;ve been relying on that for a while.  It is pretty nifty how Rails will magically parse XML post parameters, create an in-memory object and then save that object to the database without your having to write one line of code.  However, [...]]]></description>
			<content:encoded><![CDATA[<p>Rails enables web services by default, which is pretty awesome, and I&#8217;ve been relying on that for a while.  It is pretty nifty how Rails will magically parse XML post parameters, create an in-memory object and then save that object to the database without your having to write one line of code.  However, when the magic fails it can be pretty hard to debug.  I found it useful to run basic tests on the command line using curl (hearing the voice of <a href="http://simplechatter.com/">Zach Moazeni</a> in my head saying: &#8220;test your assumptions.&#8221;)
<p>Below is a writeup of the set of curl commands and sample output for testing the default Rails XML REST APIs.  This can serve as a cheat sheet for the experienced or an introduction for folks new to rails who want a basic understanding of the default webservice APIs. </p>
<p>Create an app, by typing the following commands into your terminal:</p>
<p><code><br />
$ rails basic_app<br />
$ cd basic_app<br />
$ ./script/generate scaffold  project title:string description:text<br />
$ rake db:migrate<br />
$ ./script/server<br />
</code></p>
<p>In Rails 2.3, you also need to added the following line to the top of app/controllers/projects_controller.rb (This will allow external access to the APIs.)  You can make this change while the server is running, btw.</p>
<p><code><br />
  skip_before_filter :verify_authenticity_token<br />
</code></p>
<p>Leave that window open where you can see it, since it will output useful stuff from the log.  Then in another terminal window, experiment with the following commands to interact with your application APIs.</p>
<style type="text/css">
blockquote.code {
  font-style: normal;
  font-family: Monaco,monospace;
  font-size: 12px;
  border: solid 1px #aaa;
  padding: 6px;
  background-color: #eee;
  color: inherit;
  overflow:auto;
  margin: 10px 0px;
}
</style>
<h2>Create</h2>
<p>POST /projects.xml</p>
<p>Create a project object based on the XML representation given in the post body and save in the projects database table.</p>
<blockquote class="code"><p>
$ curl -X POST -d &quot;&lt;project&gt;&lt;title&gt;Awesome&lt;/title&gt;&lt;description&gt;This is an awesome project.&lt;/description&gt;&lt;/project&gt;&quot; -H &quot;Content-Type: application/xml&quot; http://localhost:3000/projects.xml</p>
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;project&gt;<br />
&nbsp;&nbsp;&lt;created-at type=&quot;datetime&quot;&gt;2009-06-21T10:13:43-07:00&lt;/created-at&gt;<br />
&nbsp;&nbsp;&lt;description&gt;This is an awesome project.&lt;/description&gt;<br />
&nbsp;&nbsp;&lt;id type=&quot;integer&quot;&gt;6&lt;/id&gt;<br />
 &nbsp;&nbsp;&lt;title&gt;Awesome&lt;/title&gt;<br />
 &nbsp;&nbsp;&lt;updated-at type=&quot;datetime&quot;&gt;2009-06-21T10:13:43-07:00&lt;/updated-at&gt;<br />
&lt;/project&gt;
</p></blockquote>
<h2>Index</h2>
<p>GET /projects.xml</p>
<p>This returns a list of all of the projects in the database with an automatically generated XML representation.</p>
<blockquote class="code"><p>
$ curl http://localhost:3000/projects.xml&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</p>
<p>&lt;projects type=&quot;array&quot;&gt;<br />
  &lt;project&gt;<br />
    &nbsp;&nbsp;&lt;created-at type=&quot;datetime&quot;&gt;2009-06-21T10:13:19-07:00&lt;/created-at&gt;<br />
    &nbsp;&nbsp;&lt;description&gt;This is an awesome project.&lt;/description&gt;<br />
    &nbsp;&nbsp;&lt;id type=&quot;integer&quot;&gt;1&lt;/id&gt;<br />
    &nbsp;&nbsp;&lt;title&gt;Awesome&lt;/title&gt;<br />
    &nbsp;&nbsp;&lt;updated-at type=&quot;datetime&quot;&gt;2009-06-21T10:13:19-07:00&lt;/updated-at&gt;<br />
  &lt;/project&gt;<br />
  &lt;project&gt;<br />
    &nbsp;&nbsp;&lt;created-at type=&quot;datetime&quot;&gt;2009-06-21T10:13:43-07:00&lt;/created-at&gt;<br />
    &nbsp;&nbsp;&lt;description&gt;New information here&lt;/description&gt;<br />
    &nbsp;&nbsp;&lt;id type=&quot;integer&quot;&gt;2&lt;/id&gt;<br />
    &nbsp;&nbsp;&lt;title&gt;Awesome&lt;/title&gt;<br />
    &nbsp;&nbsp;&lt;updated-at type=&quot;datetime&quot;&gt;2009-06-21T10:49:21-07:00&lt;/updated-at&gt;<br />
  &lt;/project&gt;<br />
&lt;/projects&gt;
</p></blockquote>
<h2>Show</h2>
<p>GET /projects/1.xml</p>
<p>This returns an xml representation of the project with id #1</p>
<blockquote class="code"><p>
$ curl http://localhost:3000/projects/1.xml&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</p>
<p>&lt;project&gt;<br />
  &nbsp;&nbsp;&lt;created-at type=&quot;datetime&quot;&gt;2009-06-21T10:45:19-07:00&lt;/created-at&gt;<br />
  &nbsp;&nbsp;&lt;description&gt;This is an awesome project.&lt;/description&gt;<br />
  &nbsp;&nbsp;&lt;id type=&quot;integer&quot;&gt;8&lt;/id&gt;<br />
  &nbsp;&nbsp;&lt;title&gt;Awesome&lt;/title&gt;<br />
  &nbsp;&nbsp;&lt;updated-at type=&quot;datetime&quot;&gt;2009-06-21T10:45:19-07:00&lt;/updated-at&gt;<br />
&lt;/project&gt;
</p></blockquote>
<h2>Update</h2>
<p>PUT /projects/1.xml</p>
<p>This modifies the project with id #1</p>
<blockquote class="code"><p>
curl -X PUT -d &quot;&lt;project&gt;&lt;description&gt;New information here&lt;/description&gt;&lt;/project&gt;&quot; -H &quot;Content-Type: application/xml&quot; http://localhost:3000/projects/1.xml
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.ultrasaurus.com/sarahblog/2009/06/simple-web-services-with-rails/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
