<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>RailsTips - Home</title>
  <id>tag:railstips.org,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.8.0">Mephisto Drax</generator>
  
  <link href="http://railstips.org/" rel="alternate" type="text/html" />
  <updated>2008-11-20T21:35:21Z</updated>
  <geo:lat>41.650672</geo:lat><geo:long>-86.160028</geo:long><link rel="self" href="http://feeds.feedburner.com/railstips" type="application/atom+xml" /><feedburner:emailServiceId>386206</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-20:8424</id>
    <published>2008-11-20T21:30:00Z</published>
    <updated>2008-11-20T21:35:21Z</updated>
    <category term="Externals" />
    <category term="javascript" />
    <category term="jquery" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/460049624/jquery-on-rails-why-bother" rel="alternate" type="text/html" />
    <title>jQuery on Rails: Why Bother?</title>
<summary type="html">&lt;p&gt;In which I explain why I use jQuery at times and how you can as well. Oh, and I provide a wealth of links. Links are fun!&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I explain why I use jQuery at times and how you can as well. Oh, and I provide a wealth of links. Links are fun!&lt;/p&gt;
&lt;p&gt;A few people have suggested that I post about how to use &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; with Rails. I thought about it and felt that others have already covered it quite well but why not collect their posts here for you to enjoy, right? Plus, I do all my JavaScript from scatch so I do not really ever use the helpers Rails provides and as such could not post intelligently on them.&lt;/p&gt;


	&lt;h2&gt;So John, When Did You Quit Prototype?&lt;/h2&gt;


	&lt;p&gt;&lt;strong&gt;I haven’t!&lt;/strong&gt; I do not intend to ever quit using Prototype. Honestly, I have used jQuery quite a bit less than Prototype. I have found that jQuery and Prototype are both great and in different situations I will use a different library. The one thing I will say is even if you don’t actually switch to jQuery, &lt;strong&gt;I think it is important to learn new things and stretch yourself&lt;/strong&gt;. It is good to feel frustrated and like a beginner. Also, jQuery takes a very different approach which has actually helped me write better Prototype code. Hope this is helpful and not overwhelming. :)&lt;/p&gt;


	&lt;h2&gt;Creating A Plugin&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://addictedtonew.com/archives/414/creating-a-jquery-plugin-from-scratch/"&gt;&lt;img class="image right" src="http://static.railstips.org/images/a2n_jquery.jpg" alt="Addicted to New jQuery" /&gt;&lt;/a&gt;Today, I wrote an article on &lt;a href="http://addictedtonew.com/archives/414/creating-a-jquery-plugin-from-scratch/"&gt;How to Create a jQuery Plugin From Scratch&lt;/a&gt; over on my Addicted To New site. I picked out the most basic thing a plugin could do and explained each step in a lot of detail. Give it a read if you are into Prototype but are curious about jQuery.&lt;/p&gt;


	&lt;h2&gt;Live Search and Fancy Zooming&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://orderedlist.com/articles/live-search-with-quicksilver-style-for-jquery"&gt;&lt;img class="image right" src="http://static.railstips.org/images/ol_jquery.jpg" alt="Ordered List jQuery" /&gt;&lt;/a&gt;After creating my &lt;a href="http://orderedlist.com/articles/live-search-with-quicksilver-style"&gt;live search with quicksilver for prototype&lt;/a&gt; example, I decided to &lt;a href="http://orderedlist.com/articles/live-search-with-quicksilver-style-for-jquery"&gt;port it to jQuery&lt;/a&gt; (&lt;a href="http://orderedlist.com/demos/quicksilverjs/jquery/"&gt;view demo&lt;/a&gt;). Then, humbly, I was corrected by the jQuery man himself, John Resig, who re-ported my port in a &lt;a href="http://ejohn.org/blog/jquery-livesearch"&gt;more jQuery-ish functional style&lt;/a&gt;. For those that are curious, I also massaged the &lt;a href="http://github.com/jnunemaker/ajax-rdoc/tree/master"&gt;&lt;span class="caps"&gt;AJAX&lt;/span&gt;-RDoc&lt;/a&gt; project to use quicksilver searching. This is really helpful when you can’t quite remember a method name.&lt;/p&gt;


	&lt;p&gt;Likewise, when I created &lt;a href="http://orderedlist.com/articles/fancyzoom-meet-prototype"&gt;fancy zoom for prototype&lt;/a&gt;, my partner in crime, Steve Smith, created a port of &lt;a href="http://orderedlist.com/articles/fancyzoom-meet-jquery"&gt;fancy zoom for jQuery&lt;/a&gt; (&lt;a href="http://orderedlist.com/demos/fancy-zoom-jquery/"&gt;view demo&lt;/a&gt;). Fancy Zoom is great for showing text and images with an Apple-esque, in page zoom transition or even Flash if you have a video you would like to feature.&lt;/p&gt;


	&lt;h2&gt;jQuery Railscast&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://railscasts.com/episodes/136-jquery"&gt;&lt;img class="image right" src="http://static.railstips.org/images/railscasts_jquery.jpg" alt="RailsCasts jQuery" /&gt;&lt;/a&gt;Ryan Bates did an awesome job showing &lt;a href="http://railscasts.com/episodes/136-jquery"&gt;how to use the jQuery on Rails plugin with Rails&lt;/a&gt; in a recent screencast. He also gave a really quick example on how to create a plugin. I would recommend watching this and subscribing to his Railscasts, which are great.&lt;/p&gt;


	&lt;h2&gt;jRails Plugin&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://ennerchi.com/projects/jrails"&gt;&lt;img class="image right" src="http://static.railstips.org/images/jrails_jquery.jpg" alt="RailsCasts jQuery" /&gt;&lt;/a&gt;&lt;a href="http://ennerchi.com/projects/jrails"&gt;jRails&lt;/a&gt; is a drop-in jQuery replacement for Prototype/script.aculo.us on Rails. Using jRails, you can get all of the same default Rails helpers for javascript functionality using the lighter jQuery library. Ryan shows how to use it in the screencast mentioned above, but I thought I would also mention it separately. If you are a fan of the Rails javascript/ajax helpers, this plugin is for you. It makes each of them work with jQuery and has some nice demos on the site.&lt;/p&gt;


	&lt;h2&gt;Link Love&lt;/h2&gt;


	&lt;p&gt;While dispelling the &lt;a href="http://www.loudthinking.com/posts/32-myth-3-rails-forces-you-to-use-prototype"&gt;myth that Rails is tied to Prototype&lt;/a&gt;, &lt;span class="caps"&gt;DHH&lt;/span&gt; gave some jQuery examples.&lt;/p&gt;


	&lt;p&gt;Brandon showed how he &lt;a href="http://opensoul.org/2008/10/24/ajax-and-request-forgery-protection"&gt;includes the authenticity token using prototype&lt;/a&gt; and the pug automatic shows &lt;a href="http://henrik.nyh.se/2008/05/rails-authenticity-token-with-jquery"&gt;how to do the same using jQuery&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Ben Curtis has a tutorial on how to do &lt;a href="http://www.bencurtis.com/archives/2008/10/drag-and-drop-sorting-with-jquery-and-rails/"&gt;drag and drop sorting with jQuery and Rails&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Yehuda Katz has a &lt;a href="http://www.slideshare.net/wycats/jquery-presentation-to-rails-developers-110063/"&gt;year old presentation on jQuery and Rails&lt;/a&gt; that is still worth a look.&lt;/p&gt;


	&lt;p&gt;Nutrun has a more full post on &lt;a href="http://nutrun.com/weblog/unobtrusive-ajax-with-jquery-and-rails/"&gt;how to do unobtrusive ajax with jQuery and Rails&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;ErrTheBlog (errtheblog is dead. long live errtheblog!) gave jQuery some serious love a while back in their &lt;a href="http://errtheblog.com/posts/73-the-jskinny-on-jquery"&gt;jSkinny article&lt;/a&gt;. Chris also created a plugin named &lt;a href="http://famspam.com/facebox"&gt;Facebox&lt;/a&gt; that is used extensively on GitHub and has a short post that shows &lt;a href="http://ozmm.org/posts/jquery_and_respond_to.html"&gt;how to get jQuery working with respond_to&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;If you are a fan of Low Pro, Dan Webb has created a &lt;a href="http://github.com/danwrong/low-pro-for-jquery/tree/master"&gt;port of Low Pro for jQuery&lt;/a&gt;. (&lt;a href="http://www.danwebb.net/2008/1/31/low-pro-for-jquery"&gt;article #1&lt;/a&gt;, &lt;a href="http://www.danwebb.net/2008/2/3/how-to-use-low-pro-for-jquery"&gt;article #2&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;In some Rails Rumble observations, it was noted that &lt;a href="http://www.rubyrailways.com/rails-rumble-observations-part-i-jquery-on-the-heels-of-prototype/"&gt;jQuery was more widely used&lt;/a&gt; than Prototype.&lt;/p&gt;


	&lt;p&gt;Don’t forget that “&lt;a href="http://ui.jquery.com/"&gt;jQuery UI&lt;/a&gt; provides abstractions for low-level interaction and high-level, themeable widgets, built on top of the jQuery JavaScript Library, that you can use to build highly interactive web applications.” Be sure to &lt;a href="http://ui.jquery.com/demos"&gt;check out the demos&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;If you are a fan of Twitter, you can &lt;a href="http://twitter.com/jquery"&gt;follow jQuery&lt;/a&gt; for links to articles and such.&lt;/p&gt;


	&lt;p&gt;Nathan Smith gave a &lt;a href="http://www.digital-web.com/articles/jquery_crash_course/"&gt;crash course on jQuery&lt;/a&gt; that includes a &lt;a href="http://www.digital-web.com/extras/jquery_crash_course/"&gt;sweet airline seat demo&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;jQuery does not come with all of Prototype’s functionality out of the box, but you can usually &lt;a href="http://plugins.jquery.com/"&gt;find a plugin&lt;/a&gt; that does what you need if you are too lazy to make something yourself.&lt;/p&gt;


	&lt;p&gt;Lastly, one of my favorite jQuery resources is &lt;a href="http://visualjquery.com/1.1.2.html"&gt;Visual jQuery&lt;/a&gt;. I found this site a blessing when I was trying to learn jQuery.&lt;/p&gt;


	&lt;p&gt;Feel free to post your favorite jQuery/Rails resources as a comment below.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=v0XFN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=v0XFN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=E9AGN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=E9AGN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=1Ly3N"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=1Ly3N" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/460049624" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F20%2Fjquery-on-rails-why-bother</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/20/jquery-on-rails-why-bother</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>daniel</name>
    </author>
    <id>tag:railstips.org,2008-11-19:8401</id>
    <published>2008-11-19T20:35:00Z</published>
    <updated>2008-11-19T20:42:36Z</updated>
    <category term="Plugins" />
    <category term="background jobs" />
    <category term="collectiveidea" />
    <category term="delayed_job" />
    <category term="performance" />
    <category term="plugins" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/458795056/delayed-gratification-with-rails" rel="alternate" type="text/html" />
    <title>Delayed Gratification with Rails</title>
<summary type="html">&lt;p&gt;In which Daniel Morrison covers how to install and use delayed job, a rails plugin that encapsulates the common pattern of executing longer tasks in the background.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which Daniel Morrison covers how to install and use delayed job, a rails plugin that encapsulates the common pattern of executing longer tasks in the background.&lt;/p&gt;
&lt;p&gt;I realized when I started &lt;a href="http://railstips.uservoice.com"&gt;taking suggestions&lt;/a&gt; that I would not be able to do them all justice, so I asked a few of my friends to be guest authors. Daniel Morrison, of &lt;a href="http://collectiveidea.com/" title="[i] Collective Idea"&gt;Collective Idea&lt;/a&gt;, is the first and will be showing a few ways he has used delayed job to offload tasks to the background. Without any further ado, here is Dan.&lt;/p&gt;


	&lt;p&gt;At Collective Idea, we started using delayed_job a few months ago, and have fallen in love with its simplicity. In fact, my first implementation of it was done and tested on a quick train ride to Chicago, with time to spare.&lt;/p&gt;


	&lt;h2&gt; So it’s easy?&lt;/h2&gt;


	&lt;p&gt;Yep, you can add delayed_job in 10 minutes or less.&lt;/p&gt;


	&lt;h2&gt;Getting Started&lt;/h2&gt;


	&lt;p&gt;Install the plugin, &lt;a href="http://github.com/tobi/delayed_job" title="delayed_job on GitHub"&gt;which is available on GitHub&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Then build &amp; run a migration to add the delayed_jobs table:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;create_table :delayed_jobs, :force =&amp;gt; true do |table|
  table.integer  :priority, :default =&amp;gt; 0
  table.integer  :attempts, :default =&amp;gt; 0
  table.text     :handler
  table.string   :last_error
  table.datetime :run_at
  table.datetime :locked_at
  table.datetime :failed_at
  table.string   :locked_by
  table.timestamps
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(In the future there will be a generator for this step. Tobi, please merge some of the forks!)&lt;/p&gt;


	&lt;h2&gt;Run your jobs&lt;/h2&gt;


	&lt;p&gt;The rest of the article will focus on creating jobs, but when you want to run them, you can simply run &lt;code&gt;rake jobs:work&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;The job runner will grab a few jobs and run them one at a time.  It locks them so that multiple runners won’t conflict, and it will retry jobs a number of times if it fails for some reason.  If it does fail, it stores the most recent error message.  Play around in script/console with the &lt;code&gt;Delayed::Job&lt;/code&gt; model to see how it works.&lt;/p&gt;


	&lt;p&gt;There are some other ways to run jobs in production in some of the forks on github. &lt;a href="http://github.com/collectiveidea/delayed_job" title="Collective Idea's fork of delayed_job on GitHub"&gt;Collective Idea’s for example&lt;/a&gt;, adds &lt;code&gt;script/delayed_job&lt;/code&gt;.  The rake task will work for now though.&lt;/p&gt;


	&lt;h2&gt;Example 1: Delay Something&lt;/h2&gt;


	&lt;p&gt;Now the fun part: pick something to delay. A great place for delay is email. I’ve seen places where apps have broken due to email not being able to send. Maybe the client changed their email server and didn’t tell the programmer, or maybe the mail server was temporarily down for maintenance. Either way, it generally shouldn’t stop our app.&lt;/p&gt;


	&lt;p&gt;Here’s a common controller pattern for a contact form:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;def create
  @contact_form = ContactForm.new(params[:contact_form])

  if @contact_form.save
    flash[:notice] = 'Your feedback has been sent. Thanks for contacting us!'
    &lt;/code&gt;&lt;code class="ruby highlight"&gt;ContactMailer.deliver_contact_request(@contact_form)&lt;/code&gt;&lt;code class="ruby"&gt;
    redirect_to @contact_form
  else
    render :action =&amp;gt; "new" 
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The problem is that if the mailer fails due to outside circumstances, we’re throwing an error.  We could rescue from that, but since there’s nothing the user can do, we shouldn’t involve them.&lt;/p&gt;


	&lt;p&gt;Instead, let’s send email as a delayed_job, which will retry on failure and also keep track of the last error it sees.&lt;/p&gt;


	&lt;p&gt;Here’s the refactored action:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;def create
  @contact_form = ContactForm.new(params[:contact_form])

  if @contact_form.save
    flash[:notice] = 'Your feedback has been sent. Thanks for contacting us!'
    &lt;/code&gt;&lt;code class="ruby highlight"&gt;ContactMailer.send_later(:deliver_contact_request, @contact_form)&lt;/code&gt;&lt;code class="ruby"&gt;
    redirect_to @contact_form
  else
    render :action =&amp;gt; "new" 
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That’s it! &lt;code&gt;send_later&lt;/code&gt; works just like &lt;code&gt;send&lt;/code&gt;, but magically turns it into a delayed_job.  Now our user can keep clicking through the app, and the email will send in a few seconds.&lt;/p&gt;


	&lt;h2&gt;Example 2: A more complex example.&lt;/h2&gt;


	&lt;p&gt;My first use of delayed_job was a large import process that could take 5 minutes or more.  What’s going on here is the user uploads a large &lt;abbr title="Comma Separated Values"&gt;&lt;span class="caps"&gt;CSV&lt;/span&gt;&lt;/abbr&gt; file that we then processed the crap out of, adding hundreds or thousands of rows to different tables.&lt;/p&gt;


	&lt;p&gt;In my controller, I had something along these lines:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;def update
  @item = Item.find(params[:id])
  if @item.update_attributes(params[:item])
    &lt;/code&gt;&lt;code class="ruby highlight"&gt;@item.import_file.import!&lt;/code&gt;&lt;code class="ruby"&gt;
    redirect_to @item
  else
    render :action =&amp;gt; 'edit'
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The problem here is the browser has to sit and wait until the &lt;code&gt;import!&lt;/code&gt; method finishes. Not good. There’s no need for the user to wait for the import. We can give them a message in the interface that the import is still in-progress.&lt;/p&gt;


	&lt;p&gt;So change the controller method above to this:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;def update
  @item = Item.find(params[:id])
  if @item.update_attributes(params[:item])
    &lt;/code&gt;&lt;code class="ruby highlight"&gt;Delayed::Job.enqueue ImportJob.new(@item.import_file)&lt;/code&gt;&lt;code class="ruby"&gt;
    redirect_to @item
  else
    render :action =&amp;gt; 'edit'
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;code&gt;ImportJob&lt;/code&gt; is a simple class I’ve defined and tossed in the lib/ directory.

&lt;pre&gt;&lt;code class="ruby"&gt;class ImportJob
  attr_accessor :import_file_id

  def initialize(import_file)
    self.import_file_id = import_file.id
  end

  def perform
    import_file = ImportFile.find(import_file_id)
    import_file.import!
    import_file.complete!
  end    
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Again, that’s it! Our &lt;code&gt;ImportJob&lt;/code&gt;, holding our ImportFile (which is an ActiveRecord object, using attachment_fu) is added to the queue.  When we pop it off the queue later, the &lt;code&gt;perform&lt;/code&gt; method is called, which does our import. My &lt;code&gt;complete!&lt;/code&gt; method sets a &lt;code&gt;completed_at&lt;/code&gt; flag so I can tell the user that we’re done.&lt;/p&gt;


	&lt;p&gt;My real code is a bit more complex, but hopefully you can see how this style can by used for doing multi-step jobs.&lt;/p&gt;


	&lt;h2&gt;Example 3: Tiny but useful.&lt;/h2&gt;


	&lt;p&gt;The import job above adds a lot (hundreds) of locations to this app that will show up on a map eventually.  I’m using &lt;a href="http://github.com/collectiveidea/acts_as_geocodable/tree/master" title="Collective Idea's acts_as_geocodable plugin on GitHub"&gt;acts_as_geocodable&lt;/a&gt; (because it’s awesome) to geocode the addresses via Google &amp; Yahoo, but I don’t need that info right away, and I don’t need it holding up the imports.&lt;/p&gt;


	&lt;p&gt;acts_as_geocodable does its work by adding an &lt;code&gt;after_filter :attach_geocode&lt;/code&gt; automatically to the model you specify.&lt;/p&gt;


	&lt;p&gt;So for my app, I changed it from an &lt;code&gt;after_filter&lt;/code&gt; to a delayed_job.&lt;/p&gt;


	&lt;p&gt;Here’s all the code it took:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class Location &amp;lt; ActiveRecord::Base
  acts_as_geocodable

  # some code removed for clarity

  &lt;/code&gt;&lt;code class="ruby highlight"&gt;def attach_geocode_with_delay
    self.send_later(:attach_geocode_without_delay)
  end
  alias_method_chain :attach_geocode, :delay&lt;/code&gt;&lt;code class="ruby"&gt;

end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Very fun.&lt;/p&gt;


	&lt;h2&gt;Your turn&lt;/h2&gt;


	&lt;p&gt;There’s really not much more to delayed_job than that.  Its simplicity is what makes it great.  So go and delay something already!&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=dBrWN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=dBrWN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=OqodN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=OqodN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=ckh4N"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=ckh4N" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/458795056" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F19%2Fdelayed-gratification-with-rails</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/19/delayed-gratification-with-rails</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-17:8402</id>
    <published>2008-11-17T07:10:00Z</published>
    <updated>2008-11-18T04:39:36Z</updated>
    <category term="Gems" />
    <category term="Specifically Ruby" />
    <category term="gems" />
    <category term="happymapper" />
    <category term="xml" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/455693306/happymapper-making-xml-fun-again" rel="alternate" type="text/html" />
    <title>HappyMapper, Making XML Fun Again</title>
<summary type="html">&lt;p&gt;In which I show that &lt;span class="caps"&gt;XML&lt;/span&gt; does not have to suck—instead you can just HappyMap it!&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I show that &lt;span class="caps"&gt;XML&lt;/span&gt; does not have to suck—instead you can just HappyMap it!&lt;/p&gt;
&lt;p&gt;As much as &lt;a href="http://railstips.org/2008/8/12/parsing-xml-with-ruby"&gt;I write about &lt;span class="caps"&gt;XML&lt;/span&gt;&lt;/a&gt;, you would swear it is all I do, but I promise it is not. In fact, I do not really use &lt;span class="caps"&gt;XML&lt;/span&gt; that often, but I will admit that I am intrigued by it. A while back, you may remember, &lt;a href="http://railstips.org/2008/8/9/ruby-object-to-xml-mapping-library"&gt;I posted about &lt;span class="caps"&gt;ROXML&lt;/span&gt;&lt;/a&gt;, a ruby object to xml mapping library. I liked the idea but not the implementation. Soon after, I started playing around with what I have named HappyMapper, a ruby object to xml mapping library.&lt;/p&gt;


	&lt;p&gt;I wrote nearly 95% of it in a weekend and then let it sit. I let it sit so long that it started to rot. Today it hit me that I do not have to finish something in order to release it. The thing that wasn’t working was xml with a default namespace. For good reasons I am sure, libxml-ruby does not like having default namespaces. I thought to myself, you know, this library is cool even without namespace junk. I mean who even uses namespaces other than Amazon. I started to package it for release and then I noticed a few nitpicky things. I tweaked them and five hours later I had also fixed the namespace issue and changed the &lt;span class="caps"&gt;API&lt;/span&gt; a bit. So much for releasing unfinished code in hopes that someone smarter than I would finish it up…&lt;/p&gt;


	&lt;h2&gt;Examples&lt;/h2&gt;


	&lt;p&gt;But I digress, you do not care about all that, right? How about some examples? Twitter’s xml seems to be popular on this here blawg, so I will start with that. Given this xml sample from twitter:&lt;/p&gt;


&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;statuses type="array"&amp;gt; 
  &amp;lt;status&amp;gt; 
    &amp;lt;created_at&amp;gt;Sat Aug 09 05:38:12 +0000 2008&amp;lt;/created_at&amp;gt; 
    &amp;lt;id&amp;gt;882281424&amp;lt;/id&amp;gt; 
    &amp;lt;text&amp;gt;I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic.&amp;lt;/text&amp;gt; 
    &amp;lt;source&amp;gt;web&amp;lt;/source&amp;gt; 
    &amp;lt;truncated&amp;gt;false&amp;lt;/truncated&amp;gt; 
    &amp;lt;in_reply_to_status_id&amp;gt;1234&amp;lt;/in_reply_to_status_id&amp;gt; 
    &amp;lt;in_reply_to_user_id&amp;gt;12345&amp;lt;/in_reply_to_user_id&amp;gt; 
    &amp;lt;favorited&amp;gt;&amp;lt;/favorited&amp;gt; 
    &amp;lt;user&amp;gt; 
      &amp;lt;id&amp;gt;4243&amp;lt;/id&amp;gt; 
      &amp;lt;name&amp;gt;John Nunemaker&amp;lt;/name&amp;gt; 
      &amp;lt;screen_name&amp;gt;jnunemaker&amp;lt;/screen_name&amp;gt; 
      &amp;lt;location&amp;gt;Mishawaka, IN, US&amp;lt;/location&amp;gt; 
      &amp;lt;description&amp;gt;Loves his wife, ruby, notre dame football and iu basketball&amp;lt;/description&amp;gt; 
      &amp;lt;profile_image_url&amp;gt;http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg&amp;lt;/profile_image_url&amp;gt; 
      &amp;lt;url&amp;gt;http://addictedtonew.com&amp;lt;/url&amp;gt; 
      &amp;lt;protected&amp;gt;false&amp;lt;/protected&amp;gt; 
      &amp;lt;followers_count&amp;gt;486&amp;lt;/followers_count&amp;gt; 
    &amp;lt;/user&amp;gt; 
  &amp;lt;/status&amp;gt; 
&amp;lt;/statuses&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You could setup the following ruby objects:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class User
  include HappyMapper

  element :id, Integer
  element :name, String
  element :screen_name, String
  element :location, String
  element :description, String
  element :profile_image_url, String
  element :url, String
  element :protected, Boolean
  element :followers_count, Integer
end

class Status
  include HappyMapper

  element :id, Integer
  element :text, String
  element :created_at, Time
  element :source, String
  element :truncated, Boolean
  element :in_reply_to_status_id, Integer
  element :in_reply_to_user_id, Integer
  element :favorited, Boolean
  has_one :user, User
end

statuses = Status.parse(xml_string)
statuses.each do |status|
  puts status.user.name, status.user.screen_name, status.text, status.source, ''
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You can note a few things about HappyMapper from that example.&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Each xml element and attribute can be typecast.&lt;/li&gt;
		&lt;li&gt;You can define association-like elements that are formed from other HappyMapper objects (see &lt;code&gt;has_one :user, User&lt;/code&gt; in Status).&lt;/li&gt;
		&lt;li&gt;You get a parse method when including HappyMapper that takes a string and does all the magic for you.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;That was an easy one, how about something more complex and ugly, like some Amazon xml. Given some Amazon xml such as this:&lt;/p&gt;


&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"&amp;gt;
    &amp;lt;OperationRequest&amp;gt;
        &amp;lt;HTTPHeaders&amp;gt;
            &amp;lt;Header Name="UserAgent"&amp;gt;
            &amp;lt;/Header&amp;gt;
        &amp;lt;/HTTPHeaders&amp;gt;
        &amp;lt;RequestId&amp;gt;16WRJBVEM155Q026KCV1&amp;lt;/RequestId&amp;gt;
        &amp;lt;Arguments&amp;gt;
            &amp;lt;Argument Name="SearchIndex" Value="Books"&amp;gt;&amp;lt;/Argument&amp;gt;
            &amp;lt;Argument Name="Service" Value="AWSECommerceService"&amp;gt;&amp;lt;/Argument&amp;gt;
            &amp;lt;Argument Name="Title" Value="Ruby on Rails"&amp;gt;&amp;lt;/Argument&amp;gt;
            &amp;lt;Argument Name="Operation" Value="ItemSearch"&amp;gt;&amp;lt;/Argument&amp;gt;
            &amp;lt;Argument Name="AWSAccessKeyId" Value="dontbeaswoosh"&amp;gt;&amp;lt;/Argument&amp;gt;
        &amp;lt;/Arguments&amp;gt;
        &amp;lt;RequestProcessingTime&amp;gt;0.064924955368042&amp;lt;/RequestProcessingTime&amp;gt;
    &amp;lt;/OperationRequest&amp;gt;
    &amp;lt;Items&amp;gt;
        &amp;lt;Request&amp;gt;
            &amp;lt;IsValid&amp;gt;True&amp;lt;/IsValid&amp;gt;
            &amp;lt;ItemSearchRequest&amp;gt;
                &amp;lt;SearchIndex&amp;gt;Books&amp;lt;/SearchIndex&amp;gt;
                &amp;lt;Title&amp;gt;Ruby on Rails&amp;lt;/Title&amp;gt;
            &amp;lt;/ItemSearchRequest&amp;gt;
        &amp;lt;/Request&amp;gt;
        &amp;lt;TotalResults&amp;gt;22&amp;lt;/TotalResults&amp;gt;
        &amp;lt;TotalPages&amp;gt;3&amp;lt;/TotalPages&amp;gt;
        &amp;lt;Item&amp;gt;
            &amp;lt;ASIN&amp;gt;0321480791&amp;lt;/ASIN&amp;gt;
        &amp;lt;DetailPageURL&amp;gt;http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh&amp;lt;/DetailPageURL&amp;gt;
            &amp;lt;ItemAttributes&amp;gt;
                &amp;lt;Author&amp;gt;Michael Hartl&amp;lt;/Author&amp;gt;
                &amp;lt;Author&amp;gt;Aurelius Prochazka&amp;lt;/Author&amp;gt;
                &amp;lt;Manufacturer&amp;gt;Addison-Wesley Professional&amp;lt;/Manufacturer&amp;gt;
                &amp;lt;ProductGroup&amp;gt;Book&amp;lt;/ProductGroup&amp;gt;
                &amp;lt;Title&amp;gt;RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series)&amp;lt;/Title&amp;gt;
            &amp;lt;/ItemAttributes&amp;gt;
        &amp;lt;/Item&amp;gt;
    &amp;lt;/Items&amp;gt;
&amp;lt;/ItemSearchResponse&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You could create the following objects to obtain Item information:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;module PITA
  class Item
    include HappyMapper

    tag 'Item' # if you put class in module you need tag
    element :asin, String, :tag =&amp;gt; 'ASIN'
    element :detail_page_url, String, :tag =&amp;gt; 'DetailPageURL'
    element :manufacturer, String, :tag =&amp;gt; 'Manufacturer', :deep =&amp;gt; true
  end

  class Items
    include HappyMapper

    tag 'Items' # if you put class in module you need tag
    element :total_results, Integer, :tag =&amp;gt; 'TotalResults'
    element :total_pages, Integer, :tag =&amp;gt; 'TotalPages'
    has_many :items, Item
  end
end

item = PITA::Items.parse(xml_string, :single =&amp;gt; true, :use_default_namespace =&amp;gt; true)
item.items.each do |i|
  puts i.asin, i.detail_page_url, i.manufacturer, ''
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The previous example showed a few more things.&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;You can put your HappyMapper objects in a module and define the tag name (see tag ‘Item’ inside &lt;span class="caps"&gt;PITA&lt;/span&gt;::Item).&lt;/li&gt;
		&lt;li&gt;You can create nice methods for crappy camel cased xml tags (see &lt;code&gt;element :total_pages, Integer, :tag =&amp;gt; 'TotalPages'&lt;/code&gt; in &lt;span class="caps"&gt;PITA&lt;/span&gt;::Items).&lt;/li&gt;
		&lt;li&gt;There is also a has_many association-like method that allows defining a collection of HappyMapper objects. (see &lt;code&gt;has_many :items, Item&lt;/code&gt; in &lt;span class="caps"&gt;PITA&lt;/span&gt;::Items)&lt;/li&gt;
		&lt;li&gt;You do not have to map exact parent child relationships. You can go deep see diving with the :deep option on any element to pluck out grandchildren and such. (see &lt;code&gt;element :manufacturer&lt;/code&gt; in &lt;span class="caps"&gt;PITA&lt;/span&gt;::Item)&lt;/li&gt;
	&lt;/ol&gt;


	&lt;h2&gt;Installation&lt;/h2&gt;


	&lt;p&gt;Installation is typical as the gem is on rubyforge and github.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;#rubyforge
$ sudo gem install happymapper

# github
$ sudo gem install jnunemaker-happymapper&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you run into problems, feel free to fork and add some specs for the xml it is not working with. From there you can dive in and fix them or let me know and I will take a look. Think this will be handy? Got an idea? Let me know in the comments below. Oh, and yes, in the future, HappyMapper will have killer &lt;a href="http://railstips.org/2008/7/29/it-s-an-httparty-and-everyone-is-invited"&gt;HTTParty&lt;/a&gt; integration.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=D0T8N"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=D0T8N" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=xQzNN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=xQzNN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=7hnqN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=7hnqN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/455693306" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F17%2Fhappymapper-making-xml-fun-again</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/17/happymapper-making-xml-fun-again</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-14:8365</id>
    <published>2008-11-14T15:30:00Z</published>
    <updated>2008-11-18T04:38:27Z</updated>
    <category term="Gems" />
    <category term="Specifically Ruby" />
    <category term="api" />
    <category term="irc" />
    <category term="isaac" />
    <category term="sinatra" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/453047325/sinatra-for-irc" rel="alternate" type="text/html" />
    <title>Sinatra for IRC</title>
<summary type="html">&lt;p&gt;In which I extol the virtues of Isaac for working with &lt;span class="caps"&gt;IRC&lt;/span&gt; in Ruby and at the same time beg library authors to rethink their APIs.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I extol the virtues of Isaac for working with &lt;span class="caps"&gt;IRC&lt;/span&gt; in Ruby and at the same time beg library authors to rethink their APIs.&lt;/p&gt;
&lt;p&gt;My favorite &lt;a href="http://campfirenow.com"&gt;Campfire&lt;/a&gt; feature is the history. I love that it persists between Campfire sessions. On the opposite side of the spectrum, I hate that &lt;span class="caps"&gt;IRC&lt;/span&gt; doesn’t. I decided it would be nice to have a bot that sits in the room and stores all the chatter to the database. Once that was working, it would be handy to have a simple web front end that allowed searching and viewing by day. I have seen sites out there that do that but like any programmer decided to make something for myself.&lt;/p&gt;


	&lt;h2&gt;Finding Some Code&lt;/h2&gt;


	&lt;p&gt;First up, I needed to find a good &lt;span class="caps"&gt;IRC&lt;/span&gt; library for Ruby. I did research for about 30 minutes and found a ton of libraries on GitHub: &lt;a href="http://github.com/sbfaulkner/net-irc/tree/master"&gt;Net/IRC&lt;/a&gt;, &lt;a href="http://github.com/Tsion/on_irc/tree/master"&gt;on_irc&lt;/a&gt;, &lt;a href="http://github.com/dag/irc4r/tree/master"&gt;irc4r&lt;/a&gt;, &lt;a href="http://github.com/bscofield/irkr/tree/master"&gt;irkr&lt;/a&gt;, &lt;a href="http://github.com/dokipen/rbot/tree/master"&gt;rbot&lt;/a&gt;, &lt;a href="http://github.com/david/minibot/tree/master"&gt;minibot&lt;/a&gt;, &lt;a href="http://github.com/fauna/kirby/tree/master"&gt;kirby&lt;/a&gt; and &lt;a href="http://github.com/RISCfuture/autumn/tree/master"&gt;autumn&lt;/a&gt;. I even came across the &lt;a href="http://github.com/Radar/logga/tree/master"&gt;code that runs rails.loglibrary.com&lt;/a&gt;, which is kind of what I want to do but not quite. Each library did things a bit differently and they all had their strengths and weaknesses, but one thing stood out: &lt;strong&gt;they almost all required that I was familiar with &lt;span class="caps"&gt;IRC&lt;/span&gt; protocols and terminologies&lt;/strong&gt;.&lt;/p&gt;


	&lt;h2&gt;The Solution&lt;/h2&gt;


	&lt;p&gt;If I was getting paid to do this, I would want to know inside and out how things work. Because this is a side project, I just wanted to get up and running quickly. At that moment, I remembered &lt;a href="http://search.collectiveidea.com"&gt;SearchParty&lt;/a&gt; (which incidentally runs on Sinatra) and headed over there to search for &lt;a href="http://search.collectiveidea.com/search?q=irc"&gt;irc&lt;/a&gt;. Right at the top of my delicious items was &lt;a href="http://github.com/ichverstehe/isaac/tree/master"&gt;Isaac&lt;/a&gt;, which I had totally forgotten about.&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;“You want to create an &lt;span class="caps"&gt;IRC&lt;/span&gt; bot quickly? Then Isaac is you.”&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;Yes, I want to create an &lt;span class="caps"&gt;IRC&lt;/span&gt; bot quickly. That is exactly what I want to do.&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;“Be aware…a large portion of the &lt;span class="caps"&gt;IRC&lt;/span&gt; standard has not been implemented, simply because I haven’t needed it yet.”&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;I don’t care if the entire spec is implemented. All I care about is whether or not the stuff I want is implemented and what the &lt;span class="caps"&gt;API&lt;/span&gt; is in Ruby to do that stuff.&lt;/p&gt;


	&lt;h2&gt;The Code&lt;/h2&gt;


	&lt;p&gt;A few minutes later, I had the following snippet of code running which allowed my bot to login to an &lt;span class="caps"&gt;IRC&lt;/span&gt; room and listen to all the chatter. Wow. Awesome.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;
require 'rubygems'
require 'isaac'

config do |c|
  c.nick    = "fantasticalbot" 
  c.server  = "irc.freenode.net" 
  c.port    = 6667
end

on :connect do
  join "#fantasticalroom" 
end

on :channel, /.*/ do
  msg channel, "Got your message #{nick} (#{match[0]})" 
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you have used Sinatra, you can immediately see the similarities. You can even define helpers in the same way that you would with Sinatra. Now this doesn’t do everything I mentioned that I want to do, but it was a nice start. All that is left is to drop in ActiveRecord or DataMapper or implement some kind of a web hook to an app and I am good to go.&lt;/p&gt;


	&lt;h2&gt;Conclusion&lt;/h2&gt;


	&lt;p&gt;There are two points to this article. The first is that Isaac is really cool if you want to dabble with &lt;span class="caps"&gt;IRC&lt;/span&gt; from Ruby. The second point, and probably more important, is when you create a library, &lt;strong&gt;think about the &lt;span class="caps"&gt;API&lt;/span&gt; that other programmers will use more than you think about the spec you are implementing&lt;/strong&gt;. I suspect few people out there want to learn every spec that they work with. Most people are probably like me and have a simple need and want a simple solution.&lt;/p&gt;


	&lt;p&gt;This is one of the reasons &lt;a href="http://railstips.org/2008/7/29/it-s-an-httparty-and-everyone-is-invited"&gt;HTTParty&lt;/a&gt; was created and why I am now working on IMAParty. Spec is important, but every “to the spec” library needs a simplistic &lt;span class="caps"&gt;DSL&lt;/span&gt; on top that makes them easy to use for the 80% of people that only need 20% of the features.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=UZUfN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=UZUfN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=8m7UN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=8m7UN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=9RWIN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=9RWIN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/453047325" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F14%2Fsinatra-for-irc</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/14/sinatra-for-irc</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-13:8332</id>
    <published>2008-11-13T05:40:00Z</published>
    <updated>2008-11-14T15:27:37Z</updated>
    <category term="Externals" />
    <category term="Video" />
    <category term="bookmarklet" />
    <category term="javascript" />
    <category term="video" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/451481190/creating-and-integrating-bookmarklets-with-rails" rel="alternate" type="text/html" />
    <title>Creating and Integrating Bookmarklets with Rails</title>
<summary type="html">&lt;p&gt;In which I show how to create and integrate handy dandy bookmarklets with your Rails app.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I show how to create and integrate handy dandy bookmarklets with your Rails app.&lt;/p&gt;
&lt;p&gt;If your application stores information, one of the most critical keys to success is allowing users to get that information in quick. If the process is a pain, they’ll move on to something else. &lt;strong&gt;One way to allow for easy and quick data entry is a bookmarklet&lt;/strong&gt;. I recently created a couple for an app I am scratching an itch with and thought I would share the results with you.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Two FYIs&lt;/strong&gt;: For some reason I sniffed twice during the recording, but I decided to leave them both in to add some “reality.” Also, the ND YouTube tab was open because I was going to show how the tumblr bookmarklet works, not because I forgot the tab open.&lt;/p&gt;


	&lt;p&gt;&lt;img class="quicktime" src="http://railstips.org/images/qtlogo.gif" alt="Quicktime" /&gt; &lt;a href="http://video.railstips.org/creating-and-integrating-bookmarklets-with-rails/"&gt;Creating and Integrating Bookmarklets with Rails&lt;/a&gt;&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=ON3JN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=ON3JN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=llWmN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=llWmN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=p1ksN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=p1ksN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/451481190" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F13%2Fcreating-and-integrating-bookmarklets-with-rails</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/13/creating-and-integrating-bookmarklets-with-rails</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-11:8331</id>
    <published>2008-11-11T04:30:00Z</published>
    <updated>2008-11-18T04:35:13Z</updated>
    <category term="Specifically Ruby" />
    <category term="presentations" />
    <category term="rubyconf" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/449152948/rubyconf-wrapup" rel="alternate" type="text/html" />
    <title>Can't Miss RubyConf Wrapup</title>
<summary type="html">&lt;p&gt;In which I further extol the virtues of RubyConf with a wrap up post covering the final two days.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I further extol the virtues of RubyConf with a wrap up post covering the final two days.&lt;/p&gt;
&lt;p&gt;I lost the steam to write about each day individually as the last two days always seem to fly by much faster than the first. That said, here are the notes I could gather from my moleskin and varioius sheets of paper I scratched on.&lt;/p&gt;


	&lt;h2&gt;Thursday&lt;/h2&gt;


	&lt;p&gt;&lt;strong&gt;Jon Dahl&lt;/strong&gt; had an interesting talk on &lt;a href="http://railspikes.com/2008/11/7/aristotle-and-software-at-railsconf"&gt;Aristotle and Software&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Ben Scofield&lt;/strong&gt; talked about &lt;a href="http://www.culann.com/2008/11/rubyconf-doneish"&gt;All I Really Need to Know* I Learned by Writing My Own Web Framework&lt;/a&gt;. I can’t say that we need another web framework for ruby right now but I enjoyed this talk. Ben’s whole point was how much he learned by writing a web framework from scratch. I couldn’t agree more. I haven’t written my own web framework but writing pure ruby is really the best way to learn ruby. You can’t really learn ruby by just writing rails apps.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Dean Wampler&lt;/strong&gt; talked about &lt;a href="http://rubyconf.org/talks/46"&gt;Better Ruby Through Functional Programming&lt;/a&gt;. Functional programming seems really interesting. Basically, variables are immutable. Because they don’t change state, it is easier to write “side effect free” concurrent code. Recursion is big in functional programming. Basically recursion in functional programming is equivalent to loops in sequential programming (ruby is sequential). I haven’t really looked at any functional languages and I thoroughly enjoy thinking about things in a different way so this talk was good.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Jim Weirich&lt;/strong&gt; had an awesome presentation on “What Every Rubyist Should Know About Threads.” Threads were a hot topic as I mentioned in &lt;a href="http://railstips.org/2008/11/7/can-t-miss-coverage-of-rubyconf-day-1"&gt;my day one summary&lt;/a&gt;. Jim explained that &lt;a href="http://en.wikipedia.org/wiki/Moores_law"&gt;Moore’s Law&lt;/a&gt; is no longer true, so concurrency is going to be important. Instead of getting faster CPUs, computers are getting multiple CPUs. In order to fully take advantage of multiple CPUs, you have to be able to have native threads. Ruby 1.9 gets closer to native threads but isn’t there. In order to safely program concurrently in Ruby, Jim gave four tips:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Protect every shared memory access with synchronize block (check out mutex core library)&lt;/li&gt;
		&lt;li&gt;Be aware of extended situations that need to be atomic.&lt;/li&gt;
		&lt;li&gt;Need strategy to avoid deadlock.&lt;/li&gt;
		&lt;li&gt;Evaluate every line in every library used by your program, not just your own code.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;Basically, threading is hard. He gave a really quick mention of &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;, a dynamic programming language that targets the Java Virtual Machine.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Yehuda Katz&lt;/strong&gt; gave a worthwhile presentation on “Writing Code That Doesn’t Suck: Interface Oriented Design.” The talk started pretty slow and I nearly tuned out as he just covered concepts, but gave no code examples. Once he finally got to the code, I enjoyed the thoughts and examples.&lt;/p&gt;


	&lt;p&gt;The premise is that most of us test implementation more than we test results, which is what we really care about. &lt;strong&gt;Test what you do not want to break&lt;/strong&gt;. Unit testing is great for isolation but it is not regression testing. I’ve been thinking about something similar to this a lot lately since I started using RSpec on all projects, so it was interesting to hear this perspective. I’ll definitely be testing more based on results rather than on implementation in the future.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Rich Kilmer&lt;/strong&gt; presented on &lt;span class="caps"&gt;OS X&lt;/span&gt; Application Development with HotCocoa and man was it hot. HotCocoa is an awesome wrapper around &lt;a href="http://www.macruby.org/"&gt;MacRuby&lt;/a&gt; that makes building cocoa apps sane. I cannot wait to try this out. It comes bundled with MacRuby so simple install and enjoy. There is not much online about HotCocoa as it is only about 3 months old but when the video comes out give this talk a watch. You’ll be amazed. It appears to make cocoa development as easy as &lt;a href="http://railstips.org/2008/7/29/it-s-an-httparty-and-everyone-is-invited"&gt;HTTParty makes web services&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Dave Thomas&lt;/strong&gt;’ keynote fricken rocked. Basically he said we should fork ruby and try out some crazy ideas. He then recanted at the end, but the notion that ruby should be extended and played around with more was pretty interesting. The ideas he mentioned were RubyLite, Parallel Ruby (Puby or Pruby), Optionally Typed Ruby (Otuby) and Closure Based Ruby (Cluby). Cluby was really interesting. It bordered on JavaScript in places but I am a fan of JS so that did not bother me. &lt;strong&gt;Dave really challenged the community to think differently and try some stuff out&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;Thursday night after Dave’s keynote, &lt;a href="http://www.pivotallabs.com/"&gt;Pivotal Labs&lt;/a&gt; threw a poolside party in honor of &lt;a href="https://www.pivotaltracker.com"&gt;Tracker&lt;/a&gt;, which was a good time. I had a great discussion about Merb and about CouchDB with &lt;a href="http://merbist.com/"&gt;Matt Aimonetti&lt;/a&gt; and was nearly pushed into the pool, during a discussion of whether or not I should open source a sweet web analytics app I’m working on with &lt;a href="http://nonprofitchas.com"&gt;my friend Chas&lt;/a&gt;.&lt;/p&gt;


	&lt;h2&gt;Friday&lt;/h2&gt;


	&lt;p&gt;Friday I only attended one presentation, &lt;strong&gt;but it was possibly my favorite day&lt;/strong&gt;. Over lunch and through most of the afternoon, I had a great chat with &lt;a href="http://ryandaigle.com/"&gt;Ryan Daigle&lt;/a&gt;, &lt;a href="http://terralien.com/"&gt;Nathaniel Talbott&lt;/a&gt; and &lt;a href="http://nubyonrails.com"&gt;Geoff Grosenbach&lt;/a&gt;. I think often times at technical conferences we get caught up in code and miss out on a wealth of business knowledge. We talked about “to partner” or “not to partner”, predictable markets, passive income, productivity, efficiency, ideas and a whole lot more.&lt;/p&gt;


	&lt;p&gt;RubyConf was a blast this year. I finally felt comfortable pretty much the whole time and felt like I opened up a lot. &lt;strong&gt;Thanks to all who said hi and to those I did not get to meet…cheers to next year.&lt;/strong&gt;&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=jRLNN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=jRLNN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=t5BNN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=t5BNN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=LPvFN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=LPvFN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/449152948" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F11%2Frubyconf-wrapup</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/11/rubyconf-wrapup</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-11-07:8324</id>
    <published>2008-11-07T16:00:00Z</published>
    <updated>2008-11-18T04:35:49Z</updated>
    <category term="Specifically Ruby" />
    <category term="conferences" />
    <category term="presentations" />
    <category term="rubyconf" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/445608244/can-t-miss-coverage-of-rubyconf-day-1" rel="alternate" type="text/html" />
    <title>Can't Miss Coverage of RubyConf Day 1</title>
<summary type="html">&lt;p&gt;In which I cover the highs and lows of day one at RubyConf 2008 in Orlando.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I cover the highs and lows of day one at RubyConf 2008 in Orlando.&lt;/p&gt;
&lt;p&gt;So yesterday was day one of RubyConf in Orlando. I’m not keeping really detailed notes as I’m trying to pay attention more and note taking seems to hinder that but I’ll give a quick overview.&lt;/p&gt;


	&lt;h2&gt;Matz Keynote&lt;/h2&gt;


	&lt;p&gt;The day started with Matz keynote. As always, he was pleasant and pretty funny. He spoke about his reasons for ruby and confessed his love for all of us. &lt;a href="http://search.twitter.com/search?q=matz"&gt;Search twitter for Matz&lt;/a&gt; and you can find a bunch of his good quotes from the keynote.&lt;/p&gt;


	&lt;h2&gt;Gregg Pollack – Scaling Ruby&lt;/h2&gt;


	&lt;p&gt;Next up was Gregg Pollack’s talk on Scaling Ruby (without Rails). Side note: scaling does not appear to be a direct topic at the conference but threads, concurrency and distributed programming are getting some heavy coverage. &lt;strong&gt;Gregg had possibly the best put together presentation I have ever witnessed&lt;/strong&gt;. I talked to him later and he said it was all keynote but I think it was black magic.&lt;/p&gt;


	&lt;p&gt;He started by going through a wonderful explanation of threading and the benefits of single threaded vs. multi-threaded. After threading, he dove into message queues and did a wonderful demo of &lt;a href="http://github.com/starling/starling/tree/master"&gt;Starling&lt;/a&gt;. He closed the talk covering ruby prof, how to profile and some examples of what is expensive in ruby. The concepts he covered are not simple ones but Gregg did a phenomenal job of making them appear simple with great visual aides. He has a &lt;a href="http://railsenvy.com/rubyconf"&gt;pdf on the RailsEnvy site&lt;/a&gt; and &lt;a href="http://envycasts.com/products/scaling-ruby"&gt;his talk has been released&lt;/a&gt; as an EnvyCast.&lt;/p&gt;


	&lt;h2&gt;Scott Chacon – Using Git in Ruby Apps&lt;/h2&gt;


	&lt;p&gt;At RailsConf Scott did a &lt;a href="http://www.gitcasts.com/git-talk"&gt;presentation on git&lt;/a&gt; that broke the record for number of slides. This talk was not as fast paced, but I enjoyed it a lot more. It was one of those talks that instantly started firing neurons in my brain, mostly because I hadn’t really thought a lot about using Git for storage in an app. Examples Scott gave were &lt;a href="http://github.com/al3x/git-wiki/tree/master"&gt;git-wiki&lt;/a&gt;, &lt;a href="http://github.com/schacon/ticgit/wikis"&gt;ticgit&lt;/a&gt;, sqlgit and &lt;a href="http://github.com/mojombo/grit/tree/master"&gt;grit&lt;/a&gt; (which powers github).&lt;/p&gt;


	&lt;h2&gt;Jamis Buck&lt;/h2&gt;


	&lt;p&gt;Jamis did a presentation on how to say goodbye to the enterprise and embrace Ruby’s idioms. I didn’t really come from the enterprise but that is not to say that I don’t have bad habits. He had a couple of good quotes.&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I was on the dependency injection horse and riding it for all it was worth.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;I’m not into dependency injection but that cracked me up. If you don’t know what DI is, it’s ok as Jamis said you are probably better off.&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Code just in time, not just in case.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;This hit home. Often times I think what I might need down the rode but I always end up with a more complex solution than when I just create something that I need. It is far easier to add more code than to remove code at a later date.&lt;/p&gt;


	&lt;h2&gt;The Evening&lt;/h2&gt;


	&lt;p&gt;There are always a few presentations that really get me thinking, but &lt;strong&gt;the best part of any conference is hanging out with people who share the same passions&lt;/strong&gt;. In the evening, I went out to eat at Chili’s with &lt;a href="http://ryandaigle.com/"&gt;Ryan Daigle&lt;/a&gt;, &lt;a href="http://infozerk.com/"&gt;James Avery&lt;/a&gt; and &lt;a href="http://www.coreyhaines.com/coreysramblings/"&gt;Corey Haines&lt;/a&gt;. We had some rousing discussions about perfectionism, getting stuff out there, building apps, ideas, blogging and advertising.&lt;/p&gt;


	&lt;h2&gt;Conclusion&lt;/h2&gt;


	&lt;p&gt;I have found it really interesting what a &lt;strong&gt;hot topic threading is this year&lt;/strong&gt;. I have recently been reading up on Threads in ruby and how they work and I will post some stuff here at some point. It is kind of interesting to see how each conference kind of ends up with an overall theme, despite the lack of collaboration between presenters and no theme being stated by conference organizers.&lt;/p&gt;


	&lt;p&gt;Last year I &lt;a href="http://railstips.org/2007/11/8/rubyconf-2008-suggestions"&gt;blogged some suggestions for RubyConf&lt;/a&gt;. I have no idea if it helped but the name tag font size was markedly larger and it seems like things are starting a bit later. Not 10 but today’s talks started at 9:30 which is far easier to &lt;del&gt;stumble&lt;/del&gt; stroll into. That is all for day one. Nunemaker out.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=P1LeN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=P1LeN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=3aEHN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=3aEHN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=eakdN"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=eakdN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/445608244" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F11%2F7%2Fcan-t-miss-coverage-of-rubyconf-day-1</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/11/7/can-t-miss-coverage-of-rubyconf-day-1</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-28:8311</id>
    <published>2008-10-28T18:45:00Z</published>
    <updated>2008-11-18T04:35:31Z</updated>
    <category term="Externals" />
    <category term="Testing" />
    <category term="astrotrain" />
    <category term="email" />
    <category term="merb" />
    <category term="rspec" />
    <category term="web hooks" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/435013437/testing-merb-controllers-with-rspec" rel="alternate" type="text/html" />
    <title>Testing Merb Controllers with RSpec</title>
<summary type="html">&lt;p&gt;In which I discuss AstroTrain, a Merb/DataMapper, email web hook app and how I added a users controller with specs to it.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I discuss AstroTrain, a Merb/DataMapper, email web hook app and how I added a users controller with specs to it.&lt;/p&gt;
&lt;p&gt;I think &lt;a href="http://webhooks.pbwiki.com/"&gt;web hooks&lt;/a&gt; are sweet. The idea of making micro apps that take the pain out of typically painful things and allow for ridiculous re-use is really intriguing to me. In my &lt;a href="http://railstips.org/2008/10/27/using-gmail-with-imap-to-receive-email-in-rails"&gt;receiving email research&lt;/a&gt;, I came across a few web hook apps that work with email (ie: &lt;a href="http://mailhook.org/"&gt;MailHook&lt;/a&gt;). Who wants to keep messing with postfix for every app they want to receive email with? I don’t, that is for sure. That is why I got pretty stoked when I saw &lt;a href="http://techno-weenie.net"&gt;technoweenie&lt;/a&gt; start working on an email web hook app astutely named &lt;a href="http://github.com/entp/astrotrain/"&gt;AstroTrain&lt;/a&gt;. I &lt;a href="http://github.com/jnunemaker/astrotrain/tree/master"&gt;almost immediately forked it&lt;/a&gt; and started playing around.&lt;/p&gt;


	&lt;p&gt;Astrotrain is written with Merb and DataMapper. Merb has changed a lot since I last played with it so it took me a while to get my bearings. Now that I have, I’m feeling more comfortable, yet still occasionally frustrated. Because the &lt;span class="caps"&gt;API&lt;/span&gt; has changed so much, it’s kind of hard to find up to date examples of how to get things done in Merb. I’m not going to go in depth on why I did what I did, but I thought I would show the simple users controller I added to Astrotrain and the specs to make sure it is behaving. &lt;strong&gt;If there are any Merbists out there who have suggestions for making this more merb-ish, let me know in the comments and I’ll update accordingly.&lt;/strong&gt;&lt;/p&gt;


	&lt;h2&gt;app/controllers/users.rb&lt;/h2&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class Users &amp;lt; Application
  before :ensure_authenticated
  before :ensure_admin

  def index
    @users = User.all
    render
  end

  def show(id)
    @user = User.get(id)
    raise NotFound unless @user
    @mappings = @user.mappings
    render
  end

  def new
    @user = User.new
    render
  end

  def create(user)
    @user = User.new(user)
    if @user.save
      redirect url(:users), :message =&amp;gt; {:notice =&amp;gt; "User was successfully created"}
    else
      render :new
    end
  end

  def edit(id)
    @user = User.get(id)
    raise NotFound unless @user
    render
  end

  def update(user)
    @user = User.get(params[:id])
    raise NotFound unless @user
    if @user.update_attributes(user)
      redirect url(:users), :message =&amp;gt; {:notice =&amp;gt; "User was successfully updated"}
    else
      render :show
    end
  end

  def destroy(id)
    @user = User.get(id)
    raise NotFound unless @user
    if @user.destroy
      redirect url(:users)
    else
      raise InternalServerError
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;spec/controllers/users_spec.rb&lt;/h2&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')

describe "UserNotFound", :shared =&amp;gt; true do
  before do
    User.stub!(:get).and_return(nil)
  end

  it "should raise NotFound" do
    lambda {
      do_request
    }.should raise_error
  end
end

describe Users do

  describe "GET index" do
    def do_request
      dispatch_to(Users, :index) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should be successful" do
      do_request.should be_successful
    end

    it "should assign users for the view" do
      users = [mock(:user), mock(:user)]
      User.should_receive(:all).and_return(users)
      do_request.assigns(:users).should == users
    end
  end

  describe "GET show" do
    before do
      @user = mock(:user)
      @mappings = [mock(:mapping)]
      @user.stub!(:mappings).and_return(@mappings)
      User.stub!(:get).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :show, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should be successful" do
      do_request.should be_successful
    end

    it "should assign user for the view" do
      User.should_receive(:get).with('1').and_return(@user)
      do_request.assigns(:user).should == @user
    end
  end

  describe "GET show (with missing user)" do    
    def do_request
      dispatch_to(Users, :show, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it_should_behave_like 'UserNotFound'
  end

  describe "Get new" do
    before do
      @user = mock(:user)
      User.stub!(:new).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :new) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should assign user for view" do
      User.should_receive(:new).and_return(@user)
      do_request.assigns(:user).should == @user
    end

    it "should be successful" do
      do_request.should be_successful
    end
  end

  describe "POST create (with valid user)" do
    before do
      @attrs = {'login' =&amp;gt; 'jnunemaker'}
      @user = mock(:user, :save =&amp;gt; true)
      User.stub!(:new).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :create, :user =&amp;gt; @attrs) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should assign new user" do
      User.should_receive(:new).with(@attrs).and_return(@user)
      do_request.assigns(:user).should == @user
    end

    it "should save the user" do
      @user.should_receive(:save).and_return(true)
      do_request
    end

    it "should redirect" do
      do_request.should redirect_to(url(:users))
    end
  end

  describe "POST create (with invalid user)" do
    before do
      @attrs = {'login' =&amp;gt; ''}
      @user = mock(:user, :save =&amp;gt; false)
      User.stub!(:new).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :create, :user =&amp;gt; @attrs) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should assign new user" do
      User.should_receive(:new).with(@attrs).and_return(@user)
      do_request.assigns(:user).should == @user
    end

    it "should attempt to save the user" do
      @user.should_receive(:save).and_return(false)
      do_request
    end

    it "should be successful" do
      do_request.should be_successful
    end
  end

  describe "GET edit" do
    before do
      @user = mock(:user)
      @mappings = [mock(:mapping)]
      @user.stub!(:mappings).and_return(@mappings)
      User.stub!(:get).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :edit, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should be successful" do
      do_request.should be_successful
    end

    it "should assign user for the view" do
      User.should_receive(:get).with('1').and_return(@user)
      do_request.assigns(:user).should == @user
    end
  end

  describe "GET edit (with missing user)" do    
    def do_request
      dispatch_to(Users, :edit, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it_should_behave_like 'UserNotFound'
  end

  describe "PUT update (with valid user)" do
    before do
      @attrs = {'login' =&amp;gt; 'jnunemaker'}
      @user = mock(:user, :update_attributes =&amp;gt; true)
      User.stub!(:get).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :update, :id =&amp;gt; 1, :user =&amp;gt; @attrs) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should assign user" do
      User.should_receive(:get).with('1').and_return(@user)
      do_request.assigns(:user).should == @user
    end

    it "should update the user's attributes" do
      @user.should_receive(:update_attributes).and_return(true)
      do_request
    end

    it "should redirect" do
      do_request.should redirect_to(url(:users))
    end
  end

  describe "PUT update (with invalid user)" do
    before do
      @attrs = {'login' =&amp;gt; ''}
      @user = mock(:user, :update_attributes =&amp;gt; false)
      User.stub!(:get).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :update, :id =&amp;gt; 1, :user =&amp;gt; @attrs) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should assign new user" do
      User.should_receive(:get).with('1').and_return(@user)
      do_request.assigns(:user).should == @user
    end

    it "should attempt to update the user's attributes" do
      @user.should_receive(:update_attributes).and_return(false)
      do_request
    end

    it "should be successful" do
      do_request.should be_successful
    end
  end

  describe "PUT update (with missing user)" do    
    def do_request
      dispatch_to(Users, :update, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it_should_behave_like 'UserNotFound'
  end

  describe "DELETE destroy" do
    before do
      @user = mock(:users, :destroy =&amp;gt; true)
      User.stub!(:get).and_return(@user)
    end

    def do_request
      dispatch_to(Users, :destroy, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it "should find the user" do
      User.should_receive(:get).with('1').and_return(@user)
      do_request
    end

    it "should destroy the user" do
      @user.should_receive(:destroy).and_return(true)
      do_request
    end

    it "should redirect" do
      do_request.should redirect_to(url(:users))
    end
  end

  describe "DELETE destroy (with missing user)" do    
    def do_request
      dispatch_to(Users, :destroy, :id =&amp;gt; 1) do |controller|
        controller.stub!(:ensure_authenticated)
        controller.stub!(:ensure_admin)
        controller.stub!(:render)
      end
    end

    it_should_behave_like 'UserNotFound'
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I haven’t really spec’d everything. I should probably add stuff to make sure it doesn’t work if the user is not authenticated or is not an admin. It might even be good to test the views a bit, though they are pretty simple. Hope this helps others starting to dive into the  1.0 merb release candidates.&lt;/p&gt;


	&lt;p&gt;AstroTrain is only really ready for the brave but rest assured that when it is ready to hit the big time, I’ll post here again with a how to get it running and integrated with your app.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=72ghM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=72ghM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=B4XfM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=B4XfM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=Zri2M"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=Zri2M" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/435013437" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F28%2Ftesting-merb-controllers-with-rspec</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/28/testing-merb-controllers-with-rspec</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-27:8300</id>
    <published>2008-10-27T15:20:00Z</published>
    <updated>2008-10-27T15:42:56Z</updated>
    <category term="Core" />
    <category term="Externals" />
    <category term="Testing" />
    <category term="daemons" />
    <category term="email" />
    <category term="gmail" />
    <category term="god" />
    <category term="google" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/433690390/using-gmail-with-imap-to-receive-email-in-rails" rel="alternate" type="text/html" />
    <title>Using Gmail with IMAP to Receive Email in Rails</title>
<summary type="html">&lt;p&gt;In which I show how to use Gmail with &lt;span class="caps"&gt;IMAP&lt;/span&gt; to receive email in a Rails, thus avoiding having to configure or setup Postfix.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I show how to use Gmail with &lt;span class="caps"&gt;IMAP&lt;/span&gt; to receive email in a Rails, thus avoiding having to configure or setup Postfix.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://railstips.uservoice.com/"&gt;number one article suggestion&lt;/a&gt; thus far is &lt;a href="http://railstips.uservoice.com/pages/general/suggestions/36502"&gt;how to receive email in a rails app&lt;/a&gt;. Ask and you shall receive. What I am about to present is just a first run at it and I am not going to promise that it scales. :) That said, I fooled around with it a bit and found it relatively easy. I will post more on the topic as I play more with receiving email, but what follows is enough to at least get you up and running. The email address I used for this is actually a Gmail address, so using this method does not involve postfix or some other mail server configuration.&lt;/p&gt;


	&lt;h2&gt;The Project&lt;/h2&gt;


	&lt;p&gt;The project that I added email receiving functionality to was &lt;a href="http://yardvote.com/"&gt;YardVote&lt;/a&gt;, a weekend project by my friends at &lt;a href="http://collectiveidea.com"&gt;Collective Idea&lt;/a&gt;. YardVote allows people to record a “yard” with the political signs that were present in said yard and displays them on a google map. I was immediately enamored with the idea but found entering signs on my iPhone to be a bit tedious. Giving that everyone seems to be interested in receiving email, that it would be handy for yardvote, and that yardvote was open source, I decided to take a crack at it.&lt;/p&gt;


	&lt;h2&gt;The Process&lt;/h2&gt;


	&lt;p&gt;The path to success in summary form was this:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Check for new emails&lt;/li&gt;
		&lt;li&gt;Create new or update existing location from each email&lt;/li&gt;
		&lt;li&gt;Archive emails that have been processed to avoid duplicates&lt;/li&gt;
		&lt;li&gt;Turn process of checking and processing email into daemon&lt;/li&gt;
	&lt;/ol&gt;


	&lt;h2&gt;bin/mail_receiver.rb&lt;/h2&gt;


	&lt;p&gt;For whatever reason, I created a bin directory and a mail_receiver.rb script inside of that. Actually, it was for a reason. I think bin seems like a good place for stuff like this. I could have used the script directory, but I figured I would leave that for Rails and plugins. I will over comment the code below to help with any parts of it that may raise questions.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;# default rails environment to development
ENV['RAILS_ENV'] ||= 'development'
# require rails environment file which basically "boots" up rails for this script
require File.join(File.dirname(__FILE__), '..', 'config', 'environment')
require 'net/imap'
require 'net/http'

# amount of time to sleep after each loop below
SLEEP_TIME = 60

# mail.yml is the imap config for the email account (ie: username, host, etc.)
config = YAML.load(File.read(File.join(RAILS_ROOT, 'config', 'mail.yml')))

# this script will continue running forever
loop do
  begin
    # make a connection to imap account
    imap = Net::IMAP.new(config['host'], config['port'], true)
    imap.login(config['username'], config['password'])
    # select inbox as our mailbox to process
    imap.select('Inbox')

    # get all emails that are in inbox that have not been deleted
    imap.uid_search(["NOT", "DELETED"]).each do |uid|
      # fetches the straight up source of the email for tmail to parse
      source   = imap.uid_fetch(uid, ['RFC822']).first.attr['RFC822']

      # Location#new_from_email accepts the source and creates new location
      location = Location.new_from_email(source)

      # check for an existing location that matches the one created from email source
      existing = Location.existing_address(location)

      if existing
        # location exists so update the sign color to the emailed location
        existing.signs = location.signs
        if existing.save
          # existing location was updated
        else
          # existing location was invalid
        end
      elsif location.save
        # emailed location was valid and created
      else
        # emailed location was invalid
      end

      # there isn't move in imap so we copy to new mailbox and then delete from inbox
      imap.uid_copy(uid, "[Gmail]/All Mail")
      imap.uid_store(uid, "+FLAGS", [:Deleted])
    end

    # expunge removes the deleted emails
    imap.expunge
    imap.logout
    imap.disconnect

  # NoResponseError and ByResponseError happen often when imap'ing
  rescue Net::IMAP::NoResponseError =&amp;gt; e
    # send to log file, db, or email
  rescue Net::IMAP::ByeResponseError =&amp;gt; e
    # send to log file, db, or email
  rescue =&amp;gt; e
    # send to log file, db, or email
  end

  # sleep for SLEEP_TIME and then do it all over again
  sleep(SLEEP_TIME)
end&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Location#new_from_email&lt;/h2&gt;


	&lt;p&gt;The only piece of code that you might need to help what I showed above make sense is the &lt;code&gt;Location#new_from_email&lt;/code&gt; method.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class Location &amp;lt; ActiveRecord::Base
  def self.new_from_email(source)
    attrs, email = {}, TMail::Mail.parse(source)
    # set signs attribute equal to subject in proper form
    attrs[:signs]   = email.subject.blank? ? '' : email.subject.downcase.strip.titleize
    # set street equal to the body with email signatures stripped
    attrs[:street]  = parse_address(email.body)
    # create new location from the attributes
    new(attrs)
  end

  def self.parse_address(body)
    body.split("\n\n").first
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Location#new_from_email Specs&lt;/h2&gt;


	&lt;p&gt;While working on the &lt;code&gt;new_from_email&lt;/code&gt; method, I created an &lt;a href="http://github.com/jnunemaker/yardvote.com/tree/master/spec/fixtures/emails"&gt;emails directory inside fixtures&lt;/a&gt; that had several ways an email could be sent to YardVote. Then, I created a few specs to make sure that &lt;code&gt;new_from_email&lt;/code&gt; was actually working.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe Location do
  describe "#new_from_email" do
    it "should be subject" do
      location = Location.new_from_email(email_fixture(:red_no_subject))
      location.should have_error_on(:signs)
    end

    it "should require body" do
      location = Location.new_from_email(email_fixture(:red_no_body))
      location.valid?
      location.errors.full_messages.should include("We can't find a precise enough address match.")
    end

    it "should set street to email body" do
      location = Location.new_from_email(email_fixture(:red))
      location.street.should == '1600 Pennsylvania Ave. Washington, D.C.'
    end

    it "should set sign equal to subject" do
      location = Location.new_from_email(email_fixture(:red))
      location.signs.should == 'Red'
    end

    it "should work with mixed case subject" do
      location = Location.new_from_email(email_fixture(:red_mixedcase_subject))
      location.signs.should == 'Red'
    end

    it "should work with upper case subject" do
      location = Location.new_from_email(email_fixture(:red_uppercase_subject))
      location.signs.should == 'Red'
    end

    it "should work with multi line body" do
      location = Location.new_from_email(email_fixture(:red_address_two_lines))
      location.valid?
      location.to_location.to_s.should == "1600 Pennsylvania Ave Nw\nWashington, DC 20006" 
    end

    it "should work with multi line body and email signature" do
      location = Location.new_from_email(email_fixture(:red_address_two_lines_sig))
      location.valid?
      location.to_location.to_s.should == "1600 Pennsylvania Ave Nw\nWashington, DC 20006" 
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;bin/mail_receiver_ctl.rb&lt;/h2&gt;


	&lt;p&gt;Now that I could check for new email and process that email, it was time to daemonize the script. The benefit of daemonizing is that you get nice and easy start, stop and restart commands, along with a &lt;span class="caps"&gt;PID&lt;/span&gt;. The &lt;span class="caps"&gt;PID&lt;/span&gt; makes monitoring your script possible, which is needed because it is bound to crash or begin sucking up to much memory.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;require 'rubygems'
require 'daemons'
dir = File.dirname(__FILE__)
Daemons.run(dir + '/mail_receiver.rb')&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;What, you wanted more? Now you can run commands like &lt;code&gt;ruby bin/mail_receiver_ctl.rb start&lt;/code&gt; to start your script and &lt;code&gt;ruby bin/mail_receiver_ctl.rb stop&lt;/code&gt; to stop it. Very handy.&lt;/p&gt;


	&lt;h2&gt;config/mail.god&lt;/h2&gt;


	&lt;p&gt;The whole setup was running fine for a while, but sure enough, a few days later, I noticed that a few of my emails were still sitting in the inbox. This was because the script had crashed. I fiddled around with god a little bit and came up with the following script, mostly stolen from &lt;a href="http://railscasts.com/episodes/130-monitoring-with-god"&gt;Ryan Bates Railscast on god&lt;/a&gt;.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))

God.watch do |w|
  # script that needs to be run to start, stop and restart
  script          = "ruby #{RAILS_ROOT}/bin/mail_receiver_ctl.rb" 
  # attaching rails env to each script line to be sure the daemon starts in production mode
  rails_env       = "RAILS_ENV=production" 

  w.name          = "mail-receiver" 
  w.group         = "mail" 
  w.interval      = 60.seconds
  w.start         = "#{script} start #{rails_env}" 
  w.restart       = "#{script} restart #{rails_env}" 
  w.stop          = "#{script} stop #{rails_env}" 
  w.start_grace   = 20.seconds
  w.restart_grace = 20.seconds
  w.pid_file      = "#{RAILS_ROOT}/log/mail_receiver.pid" 

  w.behavior(:clean_pid_file)

  w.start_if do |start|
    start.condition(:process_running) do |c|
      c.interval = 10.seconds
      c.running = false
    end
  end

  w.restart_if do |restart|
    restart.condition(:memory_usage) do |c|
      c.above = 100.megabytes
      c.times = [3, 5]
    end

    restart.condition(:cpu_usage) do |c|
      c.above = 80.percent
      c.times = 5
    end
  end

  w.lifecycle do |on|
    on.condition(:flapping) do |c|
      c.to_state = [:start, :restart]
      c.times = 5
      c.within = 5.minute
      c.transition = :unmonitored
      c.retry_in = 10.minutes
      c.retry_times = 5
      c.retry_within = 2.hours
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;


	&lt;p&gt;Two hours, three files and a few extra methods later, YardVote could receive email. Before too long, I will be adding custom email addresses per person into an application such as Flickr and Highrise. I will be sure to post on that here, but, for now, I hope this helps people get started. Also, you can see the code actually &lt;a href="http://github.com/jnunemaker/yardvote.com/tree/master"&gt;implemented in the app on github&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I think we need to get more knowledge share on how to do things like this in Rails. If you have added receiving emails into your Rails app, how did you do it? Post a comment or link to an article that you wrote or used. Below are a few of the articles I have seen around the interwebs.&lt;/p&gt;


	&lt;h3&gt;Receiving Email in Rails links&lt;/h3&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://railspikes.com/2007/6/1/rails-email-processing"&gt;Stress-free Incoming E-Mail Processing with Rails&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://blog.craigambrose.com/past/2008/2/9/respond_toemail_or_how_to_handle/"&gt;respond_to.email, or how to handle incoming emails in rails RESTfully&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://allenfair.com/email-on-rails.pdf" title="pdf"&gt;Email on rails&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=CRcMM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=CRcMM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=l1uYM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=l1uYM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=sPXGM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=sPXGM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/433690390" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F27%2Fusing-gmail-with-imap-to-receive-email-in-rails</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/27/using-gmail-with-imap-to-receive-email-in-rails</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-22:8289</id>
    <published>2008-10-22T19:50:00Z</published>
    <updated>2008-11-17T06:38:31Z</updated>
    <category term="Site News" />
    <category term="conference" />
    <category term="free" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/428907142/free-conference-ticket" rel="alternate" type="text/html" />
    <title>Free Conference Ticket</title>
<summary type="html">&lt;p&gt;In which I give away a free conference pass to the first commenter interested.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I give away a free conference pass to the first commenter interested.&lt;/p&gt;
&lt;p&gt;I received a complimentary pass to the Voices That Matter Professional Ruby Conference in Boston November 17-20. I am going to RubyConf at the beginning of the month so I am going to pass on the free pass. &lt;strong&gt;If you are wanting to go for free, leave a comment&lt;/strong&gt; and I’ll contact you by email. First come first serve, no hoops to jump through or contests to win. I’d feel horrible letting a free ticket to anything go to waste.&lt;/p&gt;


	&lt;p&gt;The core conference costs $995, so this is a pretty sweet deal. You can &lt;a href="http://www.voicesthatmatter.com/ruby2008/"&gt;read more about the conference on the website&lt;/a&gt;. Also, if you do not get the free pass, you can use the priority code &lt;code&gt;PR2MAL4&lt;/code&gt; to receive a $200 discount, as already mentioned by the fine folks over at &lt;a href="http://railspikes.com/2008/10/14/conferences-that-matter"&gt;Rails Spikes&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; 10/24/2008 – The ticket has been claimed.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=gNgAM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=gNgAM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=ZyamM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=ZyamM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=UR4FM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=UR4FM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/428907142" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F22%2Ffree-conference-ticket</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/22/free-conference-ticket</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-22:8277</id>
    <published>2008-10-22T05:20:00Z</published>
    <updated>2008-11-18T04:35:37Z</updated>
    <category term="Specifically Ruby" />
    <category term="beginner" />
    <category term="methods" />
    <category term="private" />
    <category term="protected" />
    <category term="public" />
    <category term="visibility" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/428225675/public-indecency-protect-your-bits-and-dont-touch-my-privates" rel="alternate" type="text/html" />
    <title>Public Indecency, Protect Your Bits and Don't Touch My Privates</title>
<summary type="html">&lt;p&gt;In which I discuss method visibility and the subtle difference between protected and private in hopes of clearing things up for those new to ruby.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I discuss method visibility and the subtle difference between protected and private in hopes of clearing things up for those new to ruby.&lt;/p&gt;
&lt;p&gt;One thing that I remember as confusing when I was starting out in ruby was “protected.” I understood  the difference between private and public, but I remember protected seeming mysterious for quite a while. In the same vein as &lt;a href="http://railstips.org/2006/11/18/class-and-instance-variables-in-ruby"&gt;my class and instance variables article&lt;/a&gt;, I’ve decided to throw some examples together in hopes that those new to ruby will find it helpful. If I miss anything or am flat out wrong on something, let me know in the comments.&lt;/p&gt;


	&lt;h2&gt;Public&lt;/h2&gt;


	&lt;p&gt;If you don’t explicitly state private or protected, your methods are public. This is pretty easy to understand and the code samples below show that public methods can be called for an instance of a class, in an instance of an unrelated class and in an instance of an inherited class. In other words, you can call a public methods wherever you want.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A
  def foo
    puts 'foo in A'
  end
end

a = A.new
a.foo

class B
  def foo
    puts 'foo in B'
    a = A.new
    a.foo
  end
end

b = B.new
b.foo

class C &amp;lt; A
  def bar
    puts 'foo in C'
    foo
  end
end

c = C.new
c.bar

# Outputs: 
# foo in A
# foo in B
# foo in A
# foo in C
# foo in A&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Private&lt;/h2&gt;


	&lt;p&gt;Private methods are named that for a reason. It means that they are private to the class they belong to and cannot be used outside of that class, without using &lt;code&gt;send&lt;/code&gt;.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A
  private
    def foo
      puts 'foo in A'
    end
end

a = A.new
a.foo

# NoMethodError: private method ‘foo’ called for ...&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Likewise, as one would expect, subclassing and attempting to use a private method outside of the class definition will result in much of the same.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A
  private
    def foo
      puts 'foo in A'
    end
end

class B &amp;lt; A
end

b = B.new
b.foo

# NoMethodError: private method ‘foo’ called for ...&lt;/code&gt;&lt;/pre&gt;

	&lt;h3&gt;Valid Private Uses&lt;/h3&gt;


	&lt;p&gt;You can however use private methods inside of a class definition and inside of a subclass definition.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A
  def bar
    puts 'bar in A'
    foo
  end

  private
    def foo
      puts 'foo in A'
    end
end

class B &amp;lt; A
  def baz
    puts 'baz in B'
    foo
  end
end

a = A.new
a.bar

b = B.new
b.baz

# Outputs:
# bar in A
# foo in A
# baz in B
# foo in A&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Protected&lt;/h2&gt;


	&lt;p&gt;Protected is similar to private but has one quite subtle difference. Like private, protected cannot be used outside of the class definition.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A  
  protected
    def foo
      puts 'foo in A'
    end
end

a = A.new
a.foo

# NoMethodError: protected method ‘foo’ called for ...

class B &amp;lt; A
end

b = B.new
b.foo

# NoMethodError: protected method ‘foo’ called for ...&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Also, like private, you can use protected inside of a class definition as long as it is wrapped with a public method.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A  
  def bar
    puts 'bar in A'
    foo
  end

  protected
    def foo
      puts 'foo in A'
    end
end

a = A.new
a.bar

class B &amp;lt; A
  def baz
    puts 'baz in B'
    foo
  end
end

b = B.new
b.baz

# Outputs:
# bar in A
# foo in A
# baz in B
# foo in A&lt;/code&gt;&lt;/pre&gt;

	&lt;h3&gt;The Subtle Difference&lt;/h3&gt;


	&lt;p&gt;This is where the weird part of protected comes in. You can instantiate a class and call a protected instance method on that class inside of a subclass and things will work just fine.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A  
  protected
    def foo
      puts 'foo in A'
    end
end

class B &amp;lt; A
  def baz
    puts 'baz in B'
    a = A.new
    a.foo
  end
end

b = B.new
b.baz

# Outputs:
# baz in B
# foo in A&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The same is not true of private, however, and you will end up with a NoMethodError.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class A  
  private
    def foo
      puts 'foo in A'
    end
end

class B &amp;lt; A
  def baz
    puts 'baz in B'
    a = A.new
    a.foo
  end
end

b = B.new
b.baz

# Outputs:
# baz in B
# NoMethodError: private method ‘foo’ called for ...&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;More on Method Visibility&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby"&gt;Jamis Buck posted a great article&lt;/a&gt;  on this a while ago. I am hoping the fact that I did not use metaprogramming in my examples will help those who are just starting out and might not understand the syntax in Jamis’ post. That said, his article is definitely worth a read as well.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=p9ZWM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=p9ZWM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=fmUJM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=fmUJM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=15JJM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=15JJM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/428225675" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F22%2Fpublic-indecency-protect-your-bits-and-dont-touch-my-privates</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/22/public-indecency-protect-your-bits-and-dont-touch-my-privates</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-20:8272</id>
    <published>2008-10-20T15:35:00Z</published>
    <updated>2008-10-20T15:56:00Z</updated>
    <category term="Core" />
    <category term="Video" />
    <category term="mailers" />
    <category term="observers" />
    <category term="sweepers" />
    <category term="video" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/426546065/giving-mailers-observers-and-sweepers-their-own-space" rel="alternate" type="text/html" />
    <title>Giving Mailers, Observers and Sweepers Their Own Space</title>
<summary type="html">&lt;p&gt;In which I post my first screencast on RailsTips all about an alternate way of structuring mailers, observers and sweepers in rails.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I post my first screencast on RailsTips all about an alternate way of structuring mailers, observers and sweepers in rails.&lt;/p&gt;
&lt;p&gt;I can admit it. I am not a huge fan of video on the web, mostly because you cannot scan a video and I am a &lt;a href="http://orderedlist.com/articles/scannability-equals-profit"&gt;big time scanner&lt;/a&gt;. That said, &lt;a href="http://peepcode.com"&gt;Peepcode&lt;/a&gt; and &lt;a href="http://railscasts.com"&gt;Railscasts&lt;/a&gt; have shown me where video can really be leveraged to help someone understand a concept that would take too long to write a post about. Well, I decided to give it a whirl. I am not happy with the overall quality of the video, but it is good enough for now. I’ll work on video settings and such as I go along.&lt;/p&gt;


	&lt;h2&gt;Videos Will Have Their Own Pages&lt;/h2&gt;


	&lt;p&gt;Putting a video in the content column here would force a video too small to be worth watching, so I will be setting up separate pages for concepts that would be better covered with video. These pages will &lt;strong&gt;include code samples, related links and the embedded video&lt;/strong&gt;. Do not worry, there is not another feed to subscribe to. Each time I make a screencast, I will be sure to create a related article here.&lt;/p&gt;


	&lt;h2&gt;The First Railstips Screencast&lt;/h2&gt;


	&lt;p&gt;Ok, enough of that, on to the first screencast for RailsTips. I have &lt;strong&gt;never really liked having my mailers, observers and sweepers all pushed into app/models&lt;/strong&gt;, especially that mailers use views in app/views. Over that past months, I have amalgamated some stuff I picked up on the web and started using that instead. Let me know if you find the video helpful or have suggestions for improvements.&lt;/p&gt;


	&lt;p&gt;&lt;img class="quicktime" src="http://railstips.org/images/qtlogo.gif" alt="Quicktime" /&gt; &lt;a href="http://video.railstips.org/giving-mailers-observers-and-sweepers-their-own-space/"&gt;Giving Mailers, Observers and Sweepers Their Own Space&lt;/a&gt;&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=jnPAM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=jnPAM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=dqvBM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=dqvBM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=xTWsM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=xTWsM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/426546065" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F20%2Fgiving-mailers-observers-and-sweepers-their-own-space</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/20/giving-mailers-observers-and-sweepers-their-own-space</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-17:8260</id>
    <published>2008-10-17T16:30:00Z</published>
    <updated>2008-11-17T06:39:01Z</updated>
    <category term="Plugins" />
    <category term="action controller" />
    <category term="active record" />
    <category term="observers" />
    <category term="plugins" />
    <category term="sweepers" />
    <category term="threads" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/423871597/who-done-what-a-k-a-user-stamping" rel="alternate" type="text/html" />
    <title>Who Done What? a.k.a. User Stamping</title>
<summary type="html">&lt;p&gt;In which I discuss how to automatically stamp your models with who done it.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I discuss how to automatically stamp your models with who done it.&lt;/p&gt;
&lt;p&gt;Something I do in every app I create is add creator_id and updater_id to nearly every model. As created_at and updated_at are known as timestamping, I refer to my creator and updater attributes as “user stamping.” The annoying part is in every controller I had to assign those attributes to the currently logged in user. This isn’t a big deal but I’m lazy so I started to look for solutions.&lt;/p&gt;


	&lt;h2&gt;Thread.current&lt;/h2&gt;


	&lt;p&gt;The first thing that popped into my head was &lt;code&gt;Thread.current&lt;/code&gt;. &lt;code&gt;Thread.current&lt;/code&gt; is basically a hash that allows you to assign thread-safe key value pairs for the current thread. My thought, based on some research, was to wrap &lt;code&gt;Thread.current[:myapp_user_id]&lt;/code&gt; with &lt;code&gt;User.current&lt;/code&gt; so I could just use &lt;code&gt;User.current&lt;/code&gt; in any active record model. Only problem is that smelled a little bit and I figured would be frowned upon by the community as you really shouldn’t access request stuff in your models like that. You can &lt;a href="http://www.tutorialspoint.com/ruby/ruby_multithreading.htm"&gt;read more about threads&lt;/a&gt; and &lt;a href="http://coderrr.wordpress.com/2008/04/10/lets-stop-polluting-the-threadcurrent-hash/"&gt;Thread.current&lt;/a&gt; if you want.&lt;/p&gt;


	&lt;h2&gt;Solution: Sweeper&lt;/h2&gt;


	&lt;p&gt;I brainstormed a bit with &lt;a href="http://opensoul.org/"&gt;Brandon Keepers&lt;/a&gt; and he suggested a few things. Eventually, we decided on a sweeper as they have access to controllers which would have access to the current user. Tada! User Stamp, the plugin, was born. I whipped it together last night (&amp;lt; 50 &lt;span class="caps"&gt;LOC&lt;/span&gt;), added a few specs, and put it up on &lt;a href="http://github.com/jnunemaker/user_stamp/tree/master"&gt;github this morning&lt;/a&gt;.&lt;/p&gt;


	&lt;h2&gt;Installation&lt;/h2&gt;


	&lt;p&gt;Installation is uber predictable.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;script/plugin install git://github.com/jnunemaker/user_stamp.git&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Once plugin is installed and user_stamp call with list of models to track in application.rb.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class ApplicationController &amp;lt; ActionController::Base
  user_stamp Post, Asset, Job
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you actually want to access this stuff through associations and show it in your app you could do something like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class Post &amp;lt; ActiveRecord::Base
  belongs_to :creator, :class_name =&amp;gt; 'User'
  belongs_to :updater, :class_name =&amp;gt; 'User'
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Then, say in a view, you could do the following:&lt;/p&gt;


&lt;pre&gt;&lt;code class="erb"&gt;&amp;lt;h1&amp;gt;&amp;lt;%=h @post.name %&amp;gt;&amp;lt;/h1&amp;gt;

&amp;lt;div&amp;gt;&amp;lt;%= @post.content %&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;p&amp;gt;Posted by &amp;lt;%=h @post.creator.name %&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let me know what you think in the comments. Bugs can be reported &lt;a href="http://jnunemaker.lighthouseapp.com/projects/18403-user-stamp/overview"&gt;in lighthouse&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=vTSNM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=vTSNM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=QsG0M"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=QsG0M" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=zCRSM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=zCRSM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/423871597" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F17%2Fwho-done-what-a-k-a-user-stamping</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/17/who-done-what-a-k-a-user-stamping</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-15:8257</id>
    <published>2008-10-15T03:09:00Z</published>
    <updated>2008-11-13T05:50:07Z</updated>
    <category term="Site News" />
    <category term="feedback" />
    <category term="suggestions" />
    <category term="topics" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/421161278/suggest-topics" rel="alternate" type="text/html" />
    <title>Suggest a Topic Today</title>
<summary type="html">&lt;p&gt;In which I beg you, the fair reader, to suggest topics for me to cover. Go on, it won’t hurt. I promise.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I beg you, the fair reader, to suggest topics for me to cover. Go on, it won’t hurt. I promise.&lt;/p&gt;
&lt;p&gt;I get inspiration for topics on my own, but I thought I would also open it up to the populace. If you have a topic you’d like me to write about here, let me know. I’ve setup a &lt;a href="http://railstips.uservoice.com/"&gt;topic forum on uservoice&lt;/a&gt;. I also put a link in the header of this site that links to the uservoice forum.&lt;/p&gt;


	&lt;p&gt;I’ve seen several applications try this out and I’m curious to see if it works for blogs. If I don’t get anything over the next while I’ll take it down, but who knows, maybe you all have some good ideas. If there is anything you don’t know how to do or would like to learn more about in ruby or rails, &lt;a href="http://railstips.uservoice.com/"&gt;suggest a topic today&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update (Oct 15):&lt;/strong&gt; Wow. Already 10 topics suggested. All of them seem worthy of a post too. Fun thing is I’ll have to do some research for a couple of them as I’m not even up on the topic.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=SXieM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=SXieM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=YM0gM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=YM0gM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=cEVMM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=cEVMM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/421161278" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F15%2Fsuggest-topics</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/15/suggest-topics</feedburner:origLink></entry>
  <entry xml:base="http://railstips.org/">
    <author>
      <name>jnunemaker</name>
    </author>
    <id>tag:railstips.org,2008-10-14:8248</id>
    <published>2008-10-14T02:42:00Z</published>
    <updated>2008-10-14T02:45:20Z</updated>
    <category term="Gems" />
    <category term="Plugins" />
    <category term="gems" />
    <category term="pdf" />
    <category term="plugins" />
    <category term="prawn" />
    <link href="http://feeds.feedburner.com/~r/railstips/~3/420114152/how-to-generate-pdfs-in-rails-with-prawn" rel="alternate" type="text/html" />
    <title>How To Generate PDFs in Rails With Prawn</title>
<summary type="html">&lt;p&gt;In which I show how to use the new kid on the ruby pdf generation block, prawn, with rails.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In which I show how to use the new kid on the ruby pdf generation block, prawn, with rails.&lt;/p&gt;
&lt;p&gt;It’s been a while since I’ve needed to generate a &lt;span class="caps"&gt;PDF&lt;/span&gt; in ruby. I typically discourage clients from it because, well, I’m lazy and it’s a pain. I’ve always kind of hated pdf generation. It has always felt a tad awkward, be it in &lt;span class="caps"&gt;PHP&lt;/span&gt;, ColdFusion (6, unfortunately before cfdocument) and even Ruby. This time around, I decided to try out the new kid on the block, &lt;a href="http://prawn.majesticseacreature.com/"&gt;Prawn&lt;/a&gt;. On the website I just linked to, they recommend the &lt;a href="http://cracklabs.com/prawnto"&gt;prawnto plugin&lt;/a&gt;, so I gave it a whirl. My conclusions are that they work pretty well. Granted, I was just creating some text and formatting it, but I got up and running quickly. For your enjoyment, I’ll cover some basics below.&lt;/p&gt;


	&lt;h2&gt;Create and Install&lt;/h2&gt;


	&lt;p&gt;Note: I’m assuming Rails 2.1+. Fire up terminal and create a new app and install the prawnto plugin.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;rails prawn_demo
sudo gem install prawn
script/plugin install git://github.com/thorny-sun/prawnto.git&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now add prawn as a dependency in environment.rb.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;config.gem 'prawn'&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;For the sake of the demo we’ll need some demo data. Let’s create a Book model with some columns that we can shove lorem ipsum into.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;script/generate scaffold book title:string author:string description:text
rake db:migrate&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;BooksController#show Example&lt;/h2&gt;


	&lt;p&gt;I ran over to &lt;a href="http://pragprog.com/titles"&gt;The Pragmatic Programmer’s site&lt;/a&gt; and snagged a few titles to enter as test data. Let’s get started with something simple and add a pdf version of the show action. Open up the books controller and add &lt;code class="ruby"&gt;format.pdf { render :layout =&amp;gt; false }&lt;/code&gt; so that the action looks something like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;def show
  @book = Book.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml =&amp;gt; @book }
    format.pdf { render :layout =&amp;gt; false }
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now if you visit http://localhost:3000/books/2.pdf, you’ll get a template is missing error. Let’s add the show view. The prawnto plugin adds all the wiring, so all you need to do is create the show.pdf.prawn file inside app/views/books. For now, lets hello world that mofo with the following:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;pdf.text "Hello World!"&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now if you revisit that url, you’ll get a pdf that says hello world. Simple, eh? Let’s make the view specific to the book and tweak the look a bit.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;pdf.font "Helvetica" 
pdf.font.size = 13
pdf.text "Book: #{@book.title}", :size =&amp;gt; 16, :style =&amp;gt; :bold, :spacing =&amp;gt; 4
pdf.text "Author: #{@book.author}", :spacing =&amp;gt; 16
pdf.text @book.description&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The first two lines set the default font stuff. As you can see, &lt;code class="ruby"&gt;pdf.text&lt;/code&gt; takes a string and then a hash of options. &lt;code class="ruby"&gt;:size&lt;/code&gt; adjust the font size, &lt;code class="ruby"&gt;:style&lt;/code&gt; changes the weight, and &lt;code class="ruby"&gt;:spacing&lt;/code&gt; controls the space between lines. Pretty self-explanatory, but I thought I would cover it anyway.&lt;/p&gt;


	&lt;h2&gt;BooksController#index Example&lt;/h2&gt;


	&lt;p&gt;Now let’s create a pdf of all the books with each book on it’s own page. Add &lt;code class="ruby"&gt;format.pdf { render :layout =&amp;gt; false }&lt;/code&gt; to the respond to block in the index action and create the following index.pdf.prawn view:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;pdf.font "Helvetica" 
pdf.font.size = 13

@books.each do |book|
  pdf.text "Book: #{book.title}", :size =&amp;gt; 16, :style =&amp;gt; :bold, :spacing =&amp;gt; 4
  pdf.text "Author: #{book.author}", :spacing =&amp;gt; 16
  pdf.text book.description
  pdf.start_new_page
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So the examples I showed were pretty basic and there is a lot more you can do with prawn, but I didn’t feel like coming up with examples. Helpers work just like in views which is handy. Also, prawn does images and data tables in a pretty simple manner. Check out the &lt;a href="http://prawn.majesticseacreature.com/"&gt;prawn&lt;/a&gt; and &lt;a href="http://cracklabs.com/prawnto"&gt;prawnto&lt;/a&gt; websites for more.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/railstips?a=AFCiM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=AFCiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=qxfzM"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=qxfzM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/railstips?a=xWz1M"&gt;&lt;img src="http://feeds.feedburner.com/~f/railstips?i=xWz1M" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/railstips/~4/420114152" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=railstips&amp;itemurl=http%3A%2F%2Frailstips.org%2F2008%2F10%2F14%2Fhow-to-generate-pdfs-in-rails-with-prawn</feedburner:awareness><feedburner:origLink>http://railstips.org/2008/10/14/how-to-generate-pdfs-in-rails-with-prawn</feedburner:origLink></entry>
<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetFeedData?uri=railstips</feedburner:awareness></feed>
