<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3255107130863381139</id><updated>2011-11-30T18:23:51.658+01:00</updated><category term='ruby'/><category term='solr'/><category term='meta_search'/><category term='controllers'/><category term='blueprintcss'/><category term='shark tank'/><category term='javascript'/><category term='html5'/><category term='ec2'/><category term='daemons'/><category term='encoding'/><category term='fssm'/><category term='sort_link'/><category term='osx'/><category term='redirect_to'/><category term='boilerplate'/><category term='offsite linking'/><category term='backgroundrb'/><category term='HTTP'/><category term='memcache'/><category term='translations'/><category term='css'/><category term='git'/><category term='leopard'/><category term='gem'/><category term='amazon'/><category term='nginx'/><category term='utf8'/><category term='rails'/><category term='forms'/><category term='rmagick'/><category term='file processing'/><category term='gettext'/><category term='xss'/><category term='activemerchant'/><category term='sitemaps'/><category term='apache'/><category term='xml'/><category term='system'/><category term='i18n'/><category term='ec2onrails'/><category term='mysql'/><category term='java'/><category term='secure forms'/><category term='cookies'/><category term='xml_hidden'/><category term='ajax'/><category term='eventmachine'/><category term='rails3'/><category term='views'/><category term='erb'/><category term='rails pow development'/><category term='user authentication'/><category term='observers'/><category term='will_paginate'/><category term='rspec'/><category term='toygaroo'/><category term='ruby on rails'/><category term='link_to'/><category term='ie6'/><category term='subdomains'/><category term='checkboxes'/><category term='europe'/><category term='ssl'/><category term='devise'/><category term='222'/><category term='caching'/><category term='ubuntu'/><category term='plugins'/><category term='ultrasphinx'/><title type='text'>RoR Ramblings</title><subtitle type='html'>Just some things from my work developing RoR applications.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>58</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4730672799078933470</id><published>2011-10-30T14:13:00.002+01:00</published><updated>2011-10-30T14:15:01.538+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='solr'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='ec2'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>installing sunport_rails on ubuntu production</title><content type='html'>We've added search functionality to Toygaroo with Solr via sunspot_rails.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you are going to install it on Ubuntu then make sure you do:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;sudo apt-get install openjdk-6-jdk&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4730672799078933470?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4730672799078933470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4730672799078933470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4730672799078933470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4730672799078933470'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/10/installing-sunportrails-on-ubuntu.html' title='installing sunport_rails on ubuntu production'/><author><name>Phil</name><uri>http://www.blogger.com/profile/06847937813473558958</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3765464110360377543</id><published>2011-10-01T15:15:00.003+02:00</published><updated>2011-10-01T15:18:59.418+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='boilerplate'/><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><title type='text'>Using the html5 boilerplate and rails 3</title><content type='html'>I am experimenting with using the &lt;a href="http://html5boilerplate.com/"&gt;html5 boilerplate&lt;/a&gt; with rails 3.0x. It is an interesting setup. I am using Russ Frisch's html5 boilerplate template, but updating it to use the latest boilerplate code.&lt;div&gt;It seems to be a pretty nice way of getting your css and js ducks in a row. Over the next few days I need to see how it handles having jquery mobile in the mix. I am also not 100% sure how to use a some sort of grid layout template (like 960 or 114opx) with it. Or even if you should! &lt;/div&gt;&lt;div&gt;We shall see.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3765464110360377543?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3765464110360377543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3765464110360377543' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3765464110360377543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3765464110360377543'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/10/using-html5-boilerplate-and-rails-3.html' title='Using the html5 boilerplate and rails 3'/><author><name>Phil</name><uri>http://www.blogger.com/profile/06847937813473558958</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3203641380318565425</id><published>2011-09-28T11:44:00.003+02:00</published><updated>2011-09-28T11:48:47.008+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><title type='text'>Suffering Rails3 slowdown</title><content type='html'>We've just pushed our Rails 3 upgraded app to production... and are suffering a massive slowdown in insert/update speed over Rails 2.&lt;div&gt;At the moment I am not sure of the&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;exact cause of this. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It *might* be mysql inserts, though I can't quite see why that would be. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It *might* be because this new version we are using vestal_versions to track changes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It might be because the moon is in the house of Mars for all I know!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I hate getting stung by unknowns. The speed on our test environment is tolerable, slightly slower than the rails 2 version, but I was willing to accept that because the new version is doing so much more.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Bench-marking is one thing.. but know why the bench marks are slower is the key!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3203641380318565425?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3203641380318565425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3203641380318565425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3203641380318565425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3203641380318565425'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/09/suffering-rails3-slowdown.html' title='Suffering Rails3 slowdown'/><author><name>Phil</name><uri>http://www.blogger.com/profile/06847937813473558958</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3730925930664578155</id><published>2011-09-26T19:44:00.002+02:00</published><updated>2011-09-26T19:47:42.532+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='observers'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='daemons'/><title type='text'>Expiring fragments from daemons</title><content type='html'>We have an application that gets its data from a series of daemons that go out and read in data. This works great, except, we are caching pages. And I'd like to expire those pages based on an update.&lt;br /&gt;It turns out that an Observer doesn't have access to expire_action or fragment. And a Sweeper is not called from data-only (i.e non-controller) updates! Buggers!&lt;br /&gt;&lt;br /&gt;But there is a solution. You can call the sweeper directly from your importer:&lt;br /&gt;&lt;br /&gt;MySweeper.instance.clean_up(model_instance)&lt;br /&gt;&lt;br /&gt;This works, except I couldn't get it reliably to expire the actions. So, I used direct calls to Rails.cache.delete to do this.&lt;br /&gt;&lt;br /&gt;Thinking about it, I guess I could then have just written an observer! As those do get called from controller-less updates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3730925930664578155?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3730925930664578155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3730925930664578155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3730925930664578155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3730925930664578155'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/09/expiring-fragments-from-daemons.html' title='Expiring fragments from daemons'/><author><name>Phil</name><uri>http://www.blogger.com/profile/06847937813473558958</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-785020057787027586</id><published>2011-07-21T10:45:00.005+02:00</published><updated>2011-07-21T10:54:59.454+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='meta_search'/><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><category scheme='http://www.blogger.com/atom/ns#' term='sort_link'/><title type='text'>meta_search sort_link helper and associations</title><content type='html'>It took me a while to find this, so, for my own memory I am going to quickly write this up.&lt;br /&gt;&lt;br /&gt;I have a view that shows a table of objects (a pretty standard index view). The only issue was I want to sort on one of the columns that actually has data coming not from the main object but an association.&lt;br /&gt;What I discovered is a line in a posting &lt;a href="http://metautonomo.us/2010/11/21/metasearch-metawhere-and-rails-3-0-3/"&gt;here&lt;/a&gt; that says:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;You can define your own custom sort scopes. Define scopes named “sort_by__asc” and “sort_by__desc” and sort_link @search, :name will work as you might expect.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, I have an object of 'info' defined like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Info &amp;lt; ActiveRecord::Base&lt;br /&gt;  belongs_to :region&lt;br /&gt;  scope :contains_string, lambda {&amp;#124;str&amp;#124; where(:name.matches % &amp;quot;%#{str}%&amp;quot;)}&lt;br /&gt;  search_methods :contains_string&lt;br /&gt;&lt;br /&gt;  scope :active, lambda{where(:active =&amp;gt; true)}&lt;br /&gt;  search_methods :active, :type =&amp;gt; :boolean&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What I found is that you can put this at the end:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;scope :sort_by_region_name, lambda{joins(:region).order(&amp;quot;regions.name asc&amp;quot;)}&lt;br /&gt;search_methods :sort_by_region_name&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and then in my view I can do:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;table&amp;gt;&lt;br /&gt;    &amp;lt;thead&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td width=&amp;quot;25%&amp;quot;&amp;gt;&amp;lt;%= sort_link @info_search, :name, &amp;quot;Info&amp;quot; %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td width=&amp;quot;25%&amp;quot;&amp;gt;&amp;lt;%= sort_link @info_search, :region_name, &amp;quot;Region&amp;quot; %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;&amp;lt;%= sort_link @info_search, :active %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;/thead&amp;gt;&lt;br /&gt;        ...body info...&lt;br /&gt;&amp;lt;/table&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And in my controller:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Admin::InfosController &amp;lt; Admin::BaseController&lt;br /&gt;  def index&lt;br /&gt;    search = params[:search] &amp;#124;&amp;#124; {&amp;quot;meta_sort&amp;quot; =&amp;gt; &amp;quot;name.asc&amp;quot;}&lt;br /&gt;&lt;br /&gt;    @info_search = Info.search(search)&lt;br /&gt;    @infos = @linfo_search.paginate(:page =&amp;gt; params[:page]&amp;#124;&amp;#124;1, :per_page =&amp;gt; 15)   # load all matching records&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And presto I have an index that&lt;br /&gt;a) default to sorting by name (see the first line of the index method)&lt;br /&gt;b) let's me sort on an associated value&lt;br /&gt;&lt;br /&gt;Cool!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-785020057787027586?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/785020057787027586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=785020057787027586' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/785020057787027586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/785020057787027586'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/07/metasearch-sortlink-helper-and.html' title='meta_search sort_link helper and associations'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3883914797195623366</id><published>2011-07-01T14:50:00.003+02:00</published><updated>2011-07-01T14:53:58.431+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails pow development'/><title type='text'>I'm sorry, but POW sucks</title><content type='html'>I have been (trying to) use Pow, and the Powder gem, for a few weeks now. At the outset it looked good: you get a local domain for you test on, you don't have to worry about deployments, etc etc.&lt;br /&gt;But it sucks.&lt;br /&gt;If you get an error  in rendering (and we are using this in development, so of course this is going to happen) pow goes into a tail spin and on my MacPro it takes almost a minute to come out of it as it retries the request dozens of times.&lt;br /&gt;&lt;br /&gt;So you end up with a huge log that looks pretty much like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  SQL (2.2ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (0.9ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (0.9ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (1.0ms)  SHOW TABLES&lt;br /&gt;  SQL (1.3ms)  SHOW TABLES&lt;br /&gt;  SQL (0.9ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (0.9ms)  SHOW TABLES&lt;br /&gt;  SQL (1.4ms)  SHOW TABLES&lt;br /&gt;  SQL (1.2ms)  SHOW TABLES&lt;br /&gt;  SQL (1.4ms)  SHOW TABLES&lt;br /&gt;  SQL (1.1ms)  SHOW TABLES&lt;br /&gt;Rendered /Users/smyp/.rvm/gems/ree-1.8.7-2011.03@toygaroo_r3/gems/actionpack-3.0.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (8663.2ms)&lt;br /&gt;Rendered /Users/smyp/.rvm/gems/ree-1.8.7-2011.03@toygaroo_r3/gems/actionpack-3.0.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (8728.0ms)&lt;br /&gt;Rendered /Users/smyp/.rvm/gems/ree-1.8.7-2011.03@toygaroo_r3/gems/actionpack-3.0.3/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (22759.6ms)&lt;br /&gt;Rendered /Users/smyp/.rvm/gems/ree-1.8.7-2011.03@toygaroo_r3/gems/actionpack-3.0.3/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (22758.7ms&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I am going back to using Passenger standalone. Ok, you loose the pretty local domain, but it works much more reliably.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3883914797195623366?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3883914797195623366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3883914797195623366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3883914797195623366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3883914797195623366'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/07/im-sorry-but-pow-sucks.html' title='I&apos;m sorry, but POW sucks'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6759032117898250693</id><published>2011-05-02T15:10:00.002+02:00</published><updated>2011-05-02T15:12:38.401+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>nginx, rails and ubuntu - 502 bad gateway</title><content type='html'>We were getting tons of 502 errors under load, but then I stumbled across a posting in a news group.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;cat /proc/sys/net/core/somaxconn&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Will show you how many connections you can have. This should be 1024, because Phusion Passenger is hard coded for this value. Mine was 128!&lt;br /&gt;&lt;br /&gt;Do this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;sudo sysctl -w net.core.somaxconn=1024&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And then restart nginx.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6759032117898250693?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6759032117898250693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6759032117898250693' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6759032117898250693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6759032117898250693'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/05/nginx-rails-and-ubuntu-502-bad-gateway.html' title='nginx, rails and ubuntu - 502 bad gateway'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4616161690084041700</id><published>2011-05-01T10:24:00.003+02:00</published><updated>2011-05-01T10:32:00.687+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><title type='text'>get-flash-videos and osx (off topic)</title><content type='html'>I travel a lot and want to watch tv shows from the UK while I am doing so. There is get_iplayer that works nicely to get BBC shows, but on occasion there are things on itv (!) I watch. For this I use 'get-flash-videos'.&lt;br /&gt;&lt;br /&gt;I had a tough time getting this working on OSX, so in a nutshell here is what I did:&lt;br /&gt;&lt;br /&gt;1) Get 'get-flash-videos'&lt;br /&gt;The &lt;a href="http://code.google.com/p/get-flash-videos/"&gt;home page&lt;/a&gt; is here. You pull that down somewhere onto your mac (I have it in a Downloads/get-flash-videos directory).&lt;br /&gt;&lt;br /&gt;2) Update perl!&lt;br /&gt;This is the key! I know nothing about perl, but here is what I did:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;perl -MCPAN -e shell&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This brings up a perl shell. Perl seems to have a package manager called CPAN. You will need to update this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;install Bundle::CPAN&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you need to install Digest:SHA and Compress:ZLIB:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;install Digest::SHA1&lt;br /&gt;install Compress::Zlib&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3) FLVStreamer and rtmpdump&lt;br /&gt;Installing FLVStreamer is non-trivial and there are other guides about that. &lt;br /&gt;I download rtmpdump from &lt;a href="http://www.smallsoftware.co.uk/downloads/"&gt;here&lt;/a&gt;&lt;br /&gt;Then&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;chmod +x rtmpdump&lt;br /&gt;sudo cp rtmpdump /usr/local/bin/.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;4) Grab video!&lt;br /&gt;now you should be able to do something like:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;./get_flash_videos http://www.itv.com/itvplayer/video/?Filter=228293&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And have it pull down an mp4. I use Handbrake to convert it for playing on the ipad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4616161690084041700?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4616161690084041700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4616161690084041700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4616161690084041700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4616161690084041700'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/05/get-flash-videos-and-osx-off-topic.html' title='get-flash-videos and osx (off topic)'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1796501390043574596</id><published>2011-03-28T15:58:00.003+02:00</published><updated>2011-03-28T15:58:00.146+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='shark tank'/><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><category scheme='http://www.blogger.com/atom/ns#' term='toygaroo'/><title type='text'>Toygaroo on Rails</title><content type='html'>Seeing as there has been a lot of press recently about my company &lt;a href="http://www.toygaroo.com"&gt;Toygaroo&lt;/a&gt; I thought I might throw out some tech info for those of you who care.&lt;br /&gt;For those who don't know, Toygaroo is America's biggest toy rental company (think netflix for kid's toys). Recently - March 25th, 2011 - we appeared on the season premiere of Shark Tank - a national television show on ABC. About 4.6 million people watched the show.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Platform&lt;/span&gt;&lt;br /&gt;Toygaroo is a Ruby on Rails 3 application. It is based heavily on the code we wrote for FilmAmora.com, Spain's leading DVD rental company. We are running on Ubuntu 10.04 LTS. We're using &lt;a href="http://www.modrails.com/"&gt;Passenger 3&lt;/a&gt; and &lt;a href="http://wiki.nginx.org/"&gt;Nginx&lt;/a&gt; (doesn't everyone?!). We're using &lt;a href="https://github.com/mperham/dalli"&gt;Dalli&lt;/a&gt; in front of MemCached (though we've had some issues with this that I really should blog about!).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Host&lt;/span&gt;&lt;br /&gt;Right now we are running on Amazon EC2 service - though with &lt;a href="http://www.pcmag.com/article2/0,2817,2382636,00.asp"&gt;Mark Cuban&lt;/a&gt; coming on board that might change. I am a big fan of EC2, though I think the machines are a little underpowered for what you pay.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The numbers!&lt;/span&gt;&lt;br /&gt;In the 2 hours after the show aired we received around 70,000 page views. The basic architecture is a load balancer sitting in front of a whack of app servers. We are not using a scaling solution right now - hey, we're a start up! - so we wind up more servers if we feel we need them. It is a pretty simple process - I have a script for us to follow to get an Ubuntu server up and running in no time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Caching&lt;/span&gt;&lt;br /&gt;I looked into other solutions, like Varnish, but decided that Rails could handle the job with a combination of page, action and fragment caching. And I haven't been wrong so far. Even under heavy load we are getting great response time. The key - as I found out with FilmAmora - is what level to cache on. We cache 'blocks'. i.e. if you look at an index page with lots of toys we cache each toy block. That block can appear on many different pages, so it is a nice solution I find.&lt;br /&gt;&lt;br /&gt;As time goes on I'd like to post more about how Toygaroo is coded and running as I think it will provide a nice real world example for what you can do with Rails 3. If you have any questions drop me a line (comment on here).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1796501390043574596?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1796501390043574596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1796501390043574596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1796501390043574596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1796501390043574596'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/03/toygaroo-on-rails.html' title='Toygaroo on Rails'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6107275363052983771</id><published>2011-02-12T11:08:00.011+01:00</published><updated>2011-02-12T11:39:33.548+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='eventmachine'/><category scheme='http://www.blogger.com/atom/ns#' term='daemons'/><category scheme='http://www.blogger.com/atom/ns#' term='fssm'/><category scheme='http://www.blogger.com/atom/ns#' term='file processing'/><title type='text'>Background File Processing Daemon in Ruby</title><content type='html'>I am writing this up because I scoured the net and could not find what I would have thought would have been a common thing to do.&lt;br /&gt;We have an application that needs to watch several directories (on the server) and parse files that are placed there (via scp) by a third party. FWIW, these files represent sports betting prices. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Requirements&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A background task that could be &lt;br /&gt;* monitored&lt;br /&gt;* run forever!&lt;br /&gt;* process files instantly - parse them into ruby objects and store them into our database for use by the rails app&lt;br /&gt;&lt;br /&gt;Our Rails app is written in 2.3.x (its been running for a while) and uses Bundler.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Solution&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After some poking around I decided to use a combination of the &lt;a href="http://daemons.rubyforge.org/"&gt;Daemons&lt;/a&gt; gem, &lt;a href="http://www.railsfire.com/article/ruby-eventmachine-short-introduction"&gt;EventMachine&lt;/a&gt; and &lt;a href="https://github.com/ttilley/fssm"&gt;FSSM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The Daemon&lt;br /&gt;&lt;br /&gt;This was inspired heavily by a posting on StackOverflow.&lt;br /&gt;&lt;br /&gt;1) Install what you need&lt;br /&gt;I tried to get this working successfully with Bundler, but it was a no go. So I needed to install daemons and eventmachine 'normally':&lt;br /&gt;sudo gem install daemons eventmachine fssm&lt;br /&gt;&lt;br /&gt;2) Setup the Daemon:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Setup&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Usual stuff for a ruby file:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#!/usr/bin/env ruby&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'daemons'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We have multiple directories that need watching. So have an array:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;watch = [&lt;br /&gt;  &amp;quot;/Users/smyp/development/wl/xtf/horse&amp;quot;, &lt;br /&gt;  &amp;quot;/Users/smyp/development/wl/xtf/sport&amp;quot;,&lt;br /&gt;  &amp;quot;/Users/smyp/development/wl/xtf/live&amp;quot;,&lt;br /&gt;  &amp;quot;/Users/smyp/development/wl/xtf/alpha&amp;quot;&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;if ENV['RAILS_ENV'] == 'production'&lt;br /&gt;  watch = [&amp;quot;/home/mcdata/horse&amp;quot;, &amp;quot;/home/mcdata/sport&amp;quot;, &amp;quot;/home/mcdata/live&amp;quot;, &amp;quot;/home/mcdata/alpha&amp;quot;]&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We launch a separate daemon for each directory as we don't want a huge file in the horses directory to slow down processing in the live directory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Daemon Config&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With the daemons gem you can set things like what the process will be called. And where the pid file will reside, etc etc.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))&lt;br /&gt;&lt;br /&gt;daemon_options = {&lt;br /&gt;  :app_name   =&amp;gt; &amp;quot;xturf_file_monitor&amp;quot;,&lt;br /&gt;  :multiple   =&amp;gt; false,&lt;br /&gt;  :dir_mode   =&amp;gt; :normal,&lt;br /&gt;  :dir        =&amp;gt; File.join(dir, 'tmp', 'pids'),&lt;br /&gt;  :backtrace  =&amp;gt; true&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3) The Actual Daemon&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cue spooky music!&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class PriceDaemon&lt;br /&gt;  attr_accessor :base_dir&lt;br /&gt;  def initialize(base_dir)&lt;br /&gt;    self.base_dir = base_dir&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def dostuff&lt;br /&gt;    logger.info &amp;quot;About to start job for #{base_dir}&amp;quot;&lt;br /&gt;    EventMachine::run {&lt;br /&gt;      # Your code here&lt;br /&gt;      xhj = PriceFileJob.new(base_dir)&lt;br /&gt;      xhj.clear_backlog&lt;br /&gt;      FSSM.monitor(base_dir) do&lt;br /&gt;        create {&amp;#124;base, relative&amp;#124; xhj.clear_backlog}&lt;br /&gt;        update {&amp;#124;base, relative&amp;#124; xhj.clear_backlog}&lt;br /&gt;      end&lt;br /&gt;    }&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def logger&lt;br /&gt;    @@logger &amp;#124;&amp;#124;= ActiveSupport::BufferedLogger.new(&amp;quot;#{RAILS_ROOT}/log/price_file_monitor.log&amp;quot;)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What this does is:&lt;br /&gt;a) create a class that takes the directory to watch as an initialize parameter&lt;br /&gt;b) do an EventMachine run that first clears out any backlog files then fire up an FSSM monitor. The FSSM monitor gives us events on create, update (and delete, but we don't care about that). As a safety measure I simply trawl through the entire directory every time a file is created or updated. This ensures that anything we missed will get caught. &lt;br /&gt;We delete files ourselves after processing, so the directory should only have a few files in it anyway.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4) Spawn the Daemon&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bring on Mia Farrow!&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;watch.each_with_index do &amp;#124;base_dir, i&amp;#124;&lt;br /&gt;  Daemons.run_proc(&amp;quot;price_daemon_#{i}&amp;quot;, daemon_options) do&lt;br /&gt;    Dir.chdir dir&lt;br /&gt;    PriceDaemon.new(base_dir).dostuff&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will go through our array and file up a daemon for each directory. There are downsides to doing it this way - its not so easy to start and stop one (but then they shouldn't ever die, so if they do we just start and stop them all).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5) The File Processor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This of course will be specific to your operation, but, here's an outline of ours:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class PriceFileJob&lt;br /&gt;  attr_accessor :base_dir&lt;br /&gt;  def initialize(base_dir)&lt;br /&gt;    self.base_dir = base_dir&lt;br /&gt;    logger.info &amp;quot;watching #{base_dir}&amp;quot;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def logger&lt;br /&gt;    @@logger &amp;#124;&amp;#124;= Logger.new(&amp;quot;#{RAILS_ROOT}/log/price_file_job_#{base_dir.split(&amp;quot;/&amp;quot;).last}.log&amp;quot;, &amp;quot;daily&amp;quot;)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def clear_backlog&lt;br /&gt;    files = Dir.new(base_dir).entries.sort_by{&amp;#124;c&amp;#124; File.stat(File.join(base_dir, c)).ctime}&lt;br /&gt;    files.each do &amp;#124;file&amp;#124;&lt;br /&gt;      process_file(file)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def process_file(file)&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  private&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;6. Capistrano&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We use Capistrano to deploy, so I included some tasks in our deploy.rb&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;before "mc:release", "file_processors:stop"&lt;br /&gt;after "mc:release", "file_processors:start"&lt;br /&gt;&lt;br /&gt;namespace :file_processors do&lt;br /&gt;  desc &amp;quot;start processors&amp;quot;&lt;br /&gt;  task :start, :roles =&amp;gt; :db do&lt;br /&gt;    run &amp;quot;cd #{current_path}; RAILS_ENV=#{fetch :rails_env} ruby ./script/price_file_monitor.rb start&amp;quot;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  desc &amp;quot;get status of processors&amp;quot;&lt;br /&gt;  task :status, :roles =&amp;gt; :db do&lt;br /&gt;    run &amp;quot;cd #{current_path}; RAILS_ENV=#{fetch :rails_env} ruby ./script/price_file_monitor.rb status&amp;quot;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  desc &amp;quot;stop processors&amp;quot;&lt;br /&gt;  task :stop, :roles =&amp;gt; :db do&lt;br /&gt;    run &amp;quot;cd #{current_path}; RAILS_ENV=#{fetch :rails_env} ruby ./script/price_file_monitor.rb stop&amp;quot;&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it! I hope you found this interesting.&lt;br /&gt;&lt;br /&gt;I should also write up how we monitor these processes... maybe next time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6107275363052983771?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6107275363052983771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6107275363052983771' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6107275363052983771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6107275363052983771'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2011/02/background-file-processing-daemon-in.html' title='Background File Processing Daemon in Ruby'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1407010415264372718</id><published>2010-11-24T10:34:00.004+01:00</published><updated>2010-11-24T10:45:41.293+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='will_paginate'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><title type='text'>will_paginate and ajax in rails 3</title><content type='html'>After googling and stackoverflowing around I couldn't find anything that explicitly said how do to this.&lt;br /&gt;&lt;br /&gt;I have a page that has 'pagable' areas on it, and want to load these using ajax. And I am in rails 3!&lt;br /&gt;&lt;br /&gt;I found it actually was quite easy and only needed a few lines of code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1 - In the page view (users/show.html.erb)&lt;/span&gt;&lt;br /&gt;To enable the data-remote attribute on will_paginate's links&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;div id=&amp;quot;queue&amp;quot;&amp;gt;&amp;lt;%= render :partial =&amp;gt; 'queue' %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;$(document).ready(function() {&lt;br /&gt;    $('.pagination a').attr('data-remote', 'true');&lt;br /&gt;});&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2 - In the controller (users_controller.rb)&lt;/span&gt;&lt;br /&gt;To allow a js response&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;def show&lt;br /&gt;  @user = User.find(params[:id])&lt;br /&gt;  @queue_items = @user.queue_items.with_state(:pending).paginate(:page =&amp;gt; params[:queue_page] &amp;#124;&amp;#124; 1, :per_page =&amp;gt; 1)&lt;br /&gt;  respond_to do &amp;#124;format&amp;#124;&lt;br /&gt;    format.html &lt;br /&gt;    format.js&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3 - A show.js.erb template&lt;/span&gt;&lt;br /&gt;You need the second line to reapply the data-remote to the new links&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$('#queue').html('&amp;lt;%=escape_javascript render :partial =&amp;gt; &amp;quot;queue&amp;quot; %&amp;gt;');&lt;br /&gt;$('.pagination a').attr('data-remote', 'true');&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's it! Your new dataset should load into the 'queue' div.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1407010415264372718?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1407010415264372718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1407010415264372718' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1407010415264372718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1407010415264372718'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2010/11/willpaginate-and-ajax-in-rails-3.html' title='will_paginate and ajax in rails 3'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4161186812086370391</id><published>2010-10-18T10:46:00.005+02:00</published><updated>2010-10-18T11:03:45.014+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='devise'/><category scheme='http://www.blogger.com/atom/ns#' term='rails3'/><category scheme='http://www.blogger.com/atom/ns#' term='user authentication'/><title type='text'>Customizing Devise to a pseudo multi-stage Signup</title><content type='html'>&lt;span style="font-weight:bold;"&gt;The Requirements!&lt;/span&gt;&lt;br /&gt;On our new site we want to have a kind of multi-stage signup. The first page the user chooses a type of subscription, the second page they create their account, with address information, and the third page they enter their billing info. If they don't do the third stage that's ok as we will warn them that their account is incomplete (and they won't get any services until they give us the billing info)&lt;br /&gt;&lt;br /&gt;We are doing this new site in Rails3 and I thought I'd use &lt;a href="http://github.com/plataformatec/devise"&gt;Devise&lt;/a&gt; as the authentication engine. In our old site we use Restful Authentication, which has been awesome. But &lt;a href="http://github.com/plataformatec/devise"&gt;Devise&lt;/a&gt; seems to be the thing all the kids are into today!&lt;br /&gt;&lt;br /&gt;So here's how we did it:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 1:&lt;br /&gt;Create a New Controller&lt;br /&gt;&lt;/span&gt;We created a new controller to handle the first stage of the signup. It's very simple. It only is a "new" method (for now) as we do no saving or updating of the subscription.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;rails g controller subscriptions new&lt;br /&gt;&lt;br /&gt;      create  app/controllers/subscriptions_controller.rb&lt;br /&gt;       route  get &amp;quot;subscriptions/new&amp;quot;&lt;br /&gt;      invoke  erb&lt;br /&gt;      create    app/views/subscriptions&lt;br /&gt;      create    app/views/subscriptions/new.html.erb&lt;br /&gt;      invoke  rspec&lt;br /&gt;      create    spec/controllers/subscriptions_controller_spec.rb&lt;br /&gt;      create    spec/views/subscriptions&lt;br /&gt;      create    spec/views/subscriptions/new.html.erb_spec.rb&lt;br /&gt;      invoke  helper&lt;br /&gt;      create    app/helpers/subscriptions_helper.rb&lt;br /&gt;      invoke    rspec&lt;br /&gt;      create      spec/helpers/subscriptions_helper_spec.rb&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The controller looks like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class SubscriptionsController &amp;lt; Devise::RegistrationsController&lt;br /&gt;  def new&lt;br /&gt;    @subscription_plans = SubscriptionPlan.visible&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pretty basic stuff!&lt;br /&gt;&lt;br /&gt;The view is:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;% title &amp;quot;Sign up&amp;quot; %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div&amp;gt;Pick a subscription&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;% semantic_form_for :subscription, :url =&amp;gt; users_sign_up2_path, :html =&amp;gt; { :method =&amp;gt; :get }  do &amp;#124;form&amp;#124; %&amp;gt;&lt;br /&gt;  &amp;lt;%= form.input :plan_id, :as =&amp;gt; :radio, :collection =&amp;gt; @subscription_plans.map{&amp;#124;sp&amp;#124; [&amp;quot;#{sp.description}&amp;quot;, sp.id]} %&amp;gt;&lt;br /&gt;  &amp;lt;% form.buttons do %&amp;gt;&lt;br /&gt;    &amp;lt;%= form.commit_button &amp;quot;Continue&amp;quot; %&amp;gt;&lt;br /&gt;  &amp;lt;% end %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 2:&lt;br /&gt;Routes!&lt;br /&gt;&lt;/span&gt;We needed to add some custom routes to the users block to let Devise know what was going on:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  devise_for :users do&lt;br /&gt;    get &amp;quot;/users/sign_up&amp;quot; =&amp;gt; &amp;quot;subscriptions#new&amp;quot;&lt;br /&gt;    get &amp;quot;/users/sign_up2&amp;quot; =&amp;gt; &amp;quot;registrations#new&amp;quot;&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The first line says use the subscriptions controller as the first stage of the sign up. That way we don't need to change any helpers and can do things in the standard Devise way. The second adds the second stage - the actual user new-ing and creation:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 3:&lt;br /&gt;Override the Registrations Controller.&lt;br /&gt;&lt;/span&gt;This is where 'the good stuff' happens! Note that we don't need to override the create method. Devise has a hook in it for building the model, so we override that instead.&lt;br /&gt;It should be noted that this only works if the model can't be saved - i.e. your validations are complete. In our case we are creating 3 models in 1: subscription, address and user. The subscription and address will get saved if the user gets saved. So, we have validations in the user requiring a subscription and address. Then validations on the address to make sure it is good. That way if the validation of the address fails the validation of the user fails and we get chucked back out the the new user form.&lt;br /&gt;The code might say it better!&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class RegistrationsController &amp;lt; Devise::RegistrationsController&lt;br /&gt;  def new&lt;br /&gt;    @address = Address.new&lt;br /&gt;    begin&lt;br /&gt;      @subscription_plan = SubscriptionPlan.find(params[:subscription][:plan_id])&lt;br /&gt;    rescue Exception =&amp;gt; e&lt;br /&gt;      redirect_to users_sign_up_path and return&lt;br /&gt;    end&lt;br /&gt;    @user = User.new&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  protected&lt;br /&gt;&lt;br /&gt;    # Build a devise resource passing in the session. Useful to move&lt;br /&gt;    # temporary session data to the newly created user.&lt;br /&gt;    def build_resource(hash=nil)&lt;br /&gt;      address_info = params[:user].delete(:address) rescue {}&lt;br /&gt;      begin&lt;br /&gt;        sub_info = params[:user].delete(:subscription_plan)&lt;br /&gt;        @subscription_plan = SubscriptionPlan.find sub_info[&amp;quot;id&amp;quot;]&lt;br /&gt;      rescue Exception =&amp;gt; e&lt;br /&gt;        redirect_to users_sign_up_path and return&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      subscription = Subscription.new(:subscription_plan_id =&amp;gt; @subscription_plan.id)&lt;br /&gt;      &lt;br /&gt;      @address = Address.new(address_info.merge(:country =&amp;gt; &amp;quot;US&amp;quot;))&lt;br /&gt;      &lt;br /&gt;      @user = User.new(params[:user].merge(:first_name =&amp;gt; @address.first_name, :last_name =&amp;gt; @address.last_name))&lt;br /&gt;      @user.subscription = subscription&lt;br /&gt;      @user.current_shipping_address = @address&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def after_sign_up_path_for(resource)&lt;br /&gt;      new_user_billing_detail_path(resource)&lt;br /&gt;    end&lt;br /&gt;  &lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also note that we override 'after_sign_up_path_for'. That way we move the user onto the third stage of the process - the billing info - if they sign up.&lt;br /&gt;&lt;br /&gt;This is still in early stages, and not yet live, but the process seems to work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4161186812086370391?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4161186812086370391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4161186812086370391' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4161186812086370391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4161186812086370391'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2010/10/customizing-devise-to-pseudo-multi.html' title='Customizing Devise to a pseudo multi-stage Signup'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-102351469153766278</id><published>2010-10-14T12:26:00.003+02:00</published><updated>2010-10-14T12:30:44.470+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='activemerchant'/><title type='text'>testing Iridium gateway and active merchant with Rspec</title><content type='html'>Recently I rewrote the billing section of a website. The site uses Iridium as the gateway.&lt;br /&gt;I thought people might be interested in seeing how I spec'd this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;      context &amp;quot;iridium&amp;quot; do&lt;br /&gt;        before do&lt;br /&gt;          BillingDetail.gateway = &lt;br /&gt;            ActiveMerchant::Billing::IridiumGateway.new(&lt;br /&gt;                       :login =&amp;gt; &amp;quot;Casdasdasd&amp;quot;,&lt;br /&gt;                       :password =&amp;gt; &amp;quot;asdasdasd&amp;quot;,&lt;br /&gt;                       :enable_3d_secure =&amp;gt; true)&lt;br /&gt;        end&lt;br /&gt;        &lt;br /&gt;        it &amp;quot;should work&amp;quot; do&lt;br /&gt;          bd = Factory.build(:unsaved_billing_detail)&lt;br /&gt;&lt;br /&gt;          bd.should_receive(:ready!)&lt;br /&gt;&lt;br /&gt;          credit_card = Factory.build(:iridium_good_no_3ds)&lt;br /&gt;          address = Factory.build(:iridium_good_no_3ds_address)&lt;br /&gt;          bd.address = address&lt;br /&gt;&lt;br /&gt;          bd.authorize(100, credit_card)&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        it &amp;quot;should fail&amp;quot; do&lt;br /&gt;          bd = Factory.build(:unsaved_billing_detail)&lt;br /&gt;&lt;br /&gt;          bd.should_receive(:fail!)&lt;br /&gt;&lt;br /&gt;          credit_card = Factory.build(:iridium_card_declined)&lt;br /&gt;          address = Factory.build(:iridium_card_declined_address)&lt;br /&gt;          bd.address = address&lt;br /&gt;&lt;br /&gt;          lambda {&lt;br /&gt;            bd.authorize(100, credit_card)&lt;br /&gt;            }.should raise_error(TGR::GatewayError)&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I use FactoryGirl, so I set up some factories:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;Factory.define :iridium_good_no_3ds, :class =&amp;gt; ActiveMerchant::Billing::CreditCard do &amp;#124;cc&amp;#124;&lt;br /&gt;  cc.number &amp;quot;4976000000003436&amp;quot;&lt;br /&gt;  cc.last_name &amp;quot;Watson&amp;quot;&lt;br /&gt;  cc.first_name &amp;quot;John&amp;quot;&lt;br /&gt;  cc.verification_value &amp;quot;452&amp;quot;&lt;br /&gt;  cc.month &amp;quot;12&amp;quot;&lt;br /&gt;  cc.year &amp;quot;2012&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Factory.define :iridium_good_no_3ds_address, :class =&amp;gt; Address do &amp;#124;address&amp;#124;&lt;br /&gt;  address.last_name &amp;quot;Watson&amp;quot;&lt;br /&gt;  address.first_name &amp;quot;John&amp;quot;&lt;br /&gt;  address.address_1 &amp;quot;32 Edward Street&amp;quot;&lt;br /&gt;  address.city &amp;quot;Camborne&amp;quot;&lt;br /&gt;  address.state &amp;quot;Cornwall&amp;quot;&lt;br /&gt;  address.zipcode &amp;quot;TR14 8PA&amp;quot;&lt;br /&gt;  address.country &amp;quot;GB&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Factory.define :iridium_card_declined, :class =&amp;gt; ActiveMerchant::Billing::CreditCard do &amp;#124;cc&amp;#124;&lt;br /&gt;  cc.number &amp;quot;4921810000009076&amp;quot;&lt;br /&gt;  cc.last_name &amp;quot;Lewis&amp;quot;&lt;br /&gt;  cc.first_name &amp;quot;Jack&amp;quot;&lt;br /&gt;  cc.verification_value &amp;quot;875&amp;quot;&lt;br /&gt;  cc.month &amp;quot;12&amp;quot;&lt;br /&gt;  cc.year &amp;quot;2012&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Factory.define :iridium_card_declined_address, :class =&amp;gt; Address do &amp;#124;address&amp;#124;&lt;br /&gt;  address.last_name &amp;quot;Lewis&amp;quot;&lt;br /&gt;  address.first_name &amp;quot;Jack&amp;quot;&lt;br /&gt;  address.address_1 &amp;quot;4 Wing Road&amp;quot;&lt;br /&gt;  address.city &amp;quot;Leighton Buzzard&amp;quot;&lt;br /&gt;  address.state &amp;quot;Bedfordshire&amp;quot;&lt;br /&gt;  address.zipcode &amp;quot;LU7 0JB&amp;quot;&lt;br /&gt;  address.country &amp;quot;GB&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This seems to work a treat. I can do all my other tests using the bogus gateway, but to make sure I am actually providing the right info for Iridium this context, with its before block to set the right gateway, does the job nicely!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-102351469153766278?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/102351469153766278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=102351469153766278' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/102351469153766278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/102351469153766278'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2010/10/testing-iridium-gateway-and-active.html' title='testing Iridium gateway and active merchant with Rspec'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3043024750860345052</id><published>2010-02-26T19:54:00.003+01:00</published><updated>2010-02-26T20:00:51.037+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ec2'/><category scheme='http://www.blogger.com/atom/ns#' term='system'/><title type='text'>upgrading from ruby 1.8.6 to 1.8.7</title><content type='html'>We recently updated filmamora.com to use the latest passenger (2.2.10) and Ruby Enterprise Edition 1.8.7. This was a move from 2.2.4 and 1.8.6 respectively. (We also upgraded to Nginx 0.7.4)&lt;br /&gt;&lt;br /&gt;So far it seems to be a very worthwhile move! I had looked into using ruby 1.9, but ran into may issues with gems.&lt;br /&gt;&lt;br /&gt;Here are some Munin charts.&lt;br /&gt;&lt;br /&gt;Mysql... this I don't even understand! What a difference!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iy2w4vyQwV0/S4gZtH-T6JI/AAAAAAAAAGU/AxzLQXNguXI/s1600-h/filmamora.com-mysql_queries-week.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://2.bp.blogspot.com/_iy2w4vyQwV0/S4gZtH-T6JI/AAAAAAAAAGU/AxzLQXNguXI/s320/filmamora.com-mysql_queries-week.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442628412702451858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Memory - also seems to be a nice drop.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iy2w4vyQwV0/S4gZs4k-sgI/AAAAAAAAAGM/TZqUAxSy0KQ/s1600-h/filmamora.com-memory-week.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 264px;" src="http://4.bp.blogspot.com/_iy2w4vyQwV0/S4gZs4k-sgI/AAAAAAAAAGM/TZqUAxSy0KQ/s320/filmamora.com-memory-week.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442628408569672194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Individual Interupts&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iy2w4vyQwV0/S4gZsup2vSI/AAAAAAAAAGE/8ibeE6u-HEE/s1600-h/filmamora.com-irqstats-week.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 264px;" src="http://3.bp.blogspot.com/_iy2w4vyQwV0/S4gZsup2vSI/AAAAAAAAAGE/8ibeE6u-HEE/s320/filmamora.com-irqstats-week.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442628405905767714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Interupts&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iy2w4vyQwV0/S4gZsQmsFAI/AAAAAAAAAF8/iOUPFXynI1w/s1600-h/filmamora.com-interrupts-week.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 178px;" src="http://4.bp.blogspot.com/_iy2w4vyQwV0/S4gZsQmsFAI/AAAAAAAAAF8/iOUPFXynI1w/s320/filmamora.com-interrupts-week.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442628397839422466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The webapp itself was not changed at all. it is still using Rails 2.2.2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3043024750860345052?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3043024750860345052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3043024750860345052' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3043024750860345052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3043024750860345052'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2010/02/upgrading-from-ruby-186-to-187.html' title='upgrading from ruby 1.8.6 to 1.8.7'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iy2w4vyQwV0/S4gZtH-T6JI/AAAAAAAAAGU/AxzLQXNguXI/s72-c/filmamora.com-mysql_queries-week.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-576233544419563460</id><published>2009-12-20T10:22:00.002+01:00</published><updated>2009-12-20T10:25:18.345+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><title type='text'>SSL_Requirement</title><content type='html'>I use the ssl_requirement plugin to let me specify what actions need to be secure.&lt;br /&gt;&lt;br /&gt;But - I found it limiting. I needed to:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Specify what the secure domain was - we only have a certificate on the base domain, not all the subdomains&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Be able to easily turn it off in different environments&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;So, I forked a version off that does that. If you have the same needs (and, like me, prefer a plugin over a gem) &lt;a href="http://bit.ly/4oyKBJ"&gt;check mine out&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-576233544419563460?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/576233544419563460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=576233544419563460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/576233544419563460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/576233544419563460'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/12/sslrequirement.html' title='SSL_Requirement'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-7035620674087606867</id><published>2009-12-19T20:32:00.003+01:00</published><updated>2009-12-19T20:46:33.748+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><title type='text'>Apache + Passenger + SSL + OSX</title><content type='html'>Recently I wanted to do some work on parameter passing and also how to keep parameters passed to SSL pages through redirects.&lt;br /&gt;The first stumbling block was to get passenger and apache to play nice with SSL on OSX&lt;br /&gt;&lt;br /&gt;I am running Leopard (not SNOW Leopard) and here is what I did to get it to work. I couldn't find anything specific on the net about this, so I thought I'd chuck this up here. There may be nicer, better ways of doing this.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;1 - Create the cert&lt;/h2&gt;&lt;br /&gt;Apple has a &lt;a href="http://bit.ly/7wdxx6"&gt;page&lt;/a&gt; on creating a cert. This all worked fine except the locations aren't right. This page must be for Tiger.&lt;br /&gt;For Leopard apache is in /etc/apache2 (or /private/etc/apache2 depending on your installation).&lt;br /&gt;It all seemed to work fine for me as written apart from that.&lt;br /&gt;You end up with a ssl.key directory in your apache2 directory. You may wish to rename this domain.ssl.key if you are doing multi domain development. I am, but this is the only domain I wanted to check ssl on.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2 - Apache and SSL&lt;/h2&gt;&lt;br /&gt;This turned out to be easier than expected, but everything's easy when you know how!&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Edit /etc/apache2/httpd.conf&lt;/span&gt;&lt;br /&gt;All I needed to do is put this line around line 40:&lt;br /&gt;&lt;code&gt;Listen 80&lt;br /&gt;Listen 443&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You add the Listen 443&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3 - Passenger files&lt;/h2&gt;&lt;br /&gt;I did this by hand. As far as I know you can't do this via the prefpane,&lt;br /&gt;I have used the PrefPane to create the vhosts file.&lt;br /&gt;&lt;code&gt;sudo vi passenger_pane_vhosts/mydomain.local.vhost.conf&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then add:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;  ServerName mydomain.local&lt;br /&gt;  ServerAlias mydomain.local es.mydomain.local en.mydomain.local&lt;br /&gt;  DocumentRoot &amp;quot;/Users/smyp/development/mydomain/public&amp;quot;&lt;br /&gt;  RailsEnv development&lt;br /&gt;  &amp;lt;directory &amp;quot;/Users/smyp/development/mydomain/public&amp;quot;&amp;gt;&lt;br /&gt;    Order allow,deny&lt;br /&gt;    Allow from all&lt;br /&gt;  &amp;lt;/directory&amp;gt;&lt;br /&gt;&lt;br /&gt;# SSL Configuration&lt;br /&gt;SSLEngine on&lt;br /&gt;SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP&lt;br /&gt;SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars +StrictRequire&lt;br /&gt;&lt;br /&gt;#Self Signed certificates&lt;br /&gt;    SSLCertificateFile /private/etc/apache2/ssl.key/server.crt&lt;br /&gt;    SSLCertificateKeyFile /private/etc/apache2/ssl.key/server.key&lt;br /&gt;    SSLCertificateChainFile /private/etc/apache2/ssl.key/ca.crt&lt;br /&gt;&lt;br /&gt;SetEnvIf User-Agent &amp;quot;.*MSIE.*&amp;quot; nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0&lt;br /&gt;&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Basically what you do is copy all the stuff from the &lt;VirtualHost *:80&gt;  area and then add in the extra SSL config.&lt;br /&gt;Just point the crt, key and ca.crt files to the ones you created in step 1 from the apple doc.&lt;br /&gt;&lt;br /&gt;That's it! You should be ready to go!&lt;br /&gt;&lt;br /&gt;Let me know if there are any errors in this and I'll correct them... I wasn't making notes as I went along, so this is done from looking back, so maybe I've left something out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-7035620674087606867?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/7035620674087606867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=7035620674087606867' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7035620674087606867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7035620674087606867'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/12/apache-passenger-ssl-osx.html' title='Apache + Passenger + SSL + OSX'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2608229878059359372</id><published>2009-12-16T12:05:00.003+01:00</published><updated>2009-12-16T12:09:10.574+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='controllers'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='redirect_to'/><title type='text'>redirect_to : pass all parameters</title><content type='html'>On &lt;a href="http://filmamora.com"&gt;filmamora&lt;/a&gt; we redirect people to the language version we think they want. This is done with a subdomain for the language.&lt;br /&gt;As if that wasn't painful enough, it now seems I was stripping out additional parameters - like the parameters passed in from our mailings that triggered Google Analytics campaigns.&lt;br /&gt;Doh!&lt;br /&gt;&lt;br /&gt;So this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def language_redirect&lt;br /&gt;    redirect_to :subdomain =&amp;gt; session[:language] unless RAILS_ENV == 'staging'&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Needed to become this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def language_redirect&lt;br /&gt;    p2 = params.merge({:subdomain =&amp;gt; session[:language]})&lt;br /&gt;    redirect_to p2 unless RAILS_ENV == 'staging'&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Such a small change - such a big difference! Marketing types appeased!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2608229878059359372?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2608229878059359372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2608229878059359372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2608229878059359372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2608229878059359372'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/12/redirectto-pass-all-parameters.html' title='redirect_to : pass all parameters'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3083600308958818934</id><published>2009-10-06T15:01:00.002+02:00</published><updated>2009-10-06T15:03:48.266+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><category scheme='http://www.blogger.com/atom/ns#' term='ec2'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>rotating nginx logs</title><content type='html'>Since moving most of my systems over to plain Ubuntu on EC2 (as opposed to using ec2OnRails) I've needed to figure out certain things - like rotating the nginx logs (using Nginx instead of apache).&lt;br /&gt;&lt;br /&gt;Simply create a file in &lt;code&gt;/etc/logrotate.d/nginx&lt;/code&gt; that looks like this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/opt/nginx/logs/*.log {&lt;br /&gt;  daily&lt;br /&gt;  missingok&lt;br /&gt;  rotate 30&lt;br /&gt;  compress&lt;br /&gt;  delaycompress&lt;br /&gt;  sharedscripts&lt;br /&gt;  postrotate&lt;br /&gt;    /etc/init.d/nginx restart&lt;br /&gt;  endscript&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3083600308958818934?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3083600308958818934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3083600308958818934' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3083600308958818934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3083600308958818934'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/10/rotating-nginx-logs.html' title='rotating nginx logs'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1410467772159458124</id><published>2009-07-24T15:05:00.002+02:00</published><updated>2009-07-24T15:09:09.586+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>move from ec2onrails</title><content type='html'>Recently the performance on FilmAmora.com has been plummeting. And I had no idea why. Often apache was timing out waiting for a mongrel. Very little development has happened recently on FilmAmora, so I was stumped.&lt;br /&gt;So - like a good developer - I took this as a chance to make a drastic move from ec2onrails machines to straight ubuntu, with everything else installed by hand.&lt;br /&gt;&lt;br /&gt;It has made a HUGE difference. So much so that I could actually drop a machine from the configuration and still have better response times.&lt;br /&gt;&lt;br /&gt;I followed these instructions to get started: &lt;a href="http://github.com/jnstq/rails-nginx-passenger-ubuntu/tree/master"&gt;rails-nginx-passenger-ubuntu&lt;/a&gt;. I also switched to nginx and ruby enterprise edition - just to make following the instructions easier.&lt;br /&gt;&lt;br /&gt;So far so good. It took a couple hours and presto a leaner meaner installation. My NewRelic Apdex score went from .5 to .9.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1410467772159458124?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1410467772159458124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1410467772159458124' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1410467772159458124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1410467772159458124'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/07/move-from-ec2onrails.html' title='move from ec2onrails'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-9108285204043218899</id><published>2009-07-17T12:10:00.001+02:00</published><updated>2009-07-17T12:10:38.761+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>expiring action_cache</title><content type='html'>I was having a bugger of a time expiring my cache. The problem was the cache_path.&lt;br /&gt;I have index actions that take filters. So, I created a cache_path for my action caching:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;caches_action :index, :layout =&amp;gt; false, :cache_path =&amp;gt; Proc.new { &amp;#124;c&amp;#124; &amp;quot;#{c.params[:league_id]}/index/#{c.params.values.sort.to_s}&amp;quot; }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which means that all my caches end up in a nice tree of 'views/[league name]'. But, how to expire a whole part of the cache tree when there could be dozens of nodes as people could be searching on last names too.&lt;br /&gt;&lt;br /&gt;What I found was that expire_action was NOT the way to go. expire_fragment lets you pass in a regular expression. Now in my sweeper I have this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def expire_cache_for(player)&lt;br /&gt;    expire_fragment(%r{views/#{player.league.to_param}.*})&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which will expire all the cached code for the player's league.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-9108285204043218899?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/9108285204043218899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=9108285204043218899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9108285204043218899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9108285204043218899'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/07/expiring-actioncache.html' title='expiring action_cache'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-7879212348631644002</id><published>2009-06-23T22:36:00.002+02:00</published><updated>2009-06-23T23:43:53.272+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rmagick'/><title type='text'>installing rmagick on osx leopard</title><content type='html'>I've put up a gist of a bash file that works (as of today) to do this from source.&lt;br /&gt;You can clone it:&lt;br /&gt;&lt;br /&gt;git clone git://gist.github.com/134823.git gist-134823&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-7879212348631644002?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/7879212348631644002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=7879212348631644002' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7879212348631644002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7879212348631644002'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/06/imstalling-rmagick-on-osx-leopard.html' title='installing rmagick on osx leopard'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-145175717272873143</id><published>2009-06-21T20:24:00.000+02:00</published><updated>2009-06-21T20:25:28.052+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>nerdy but funny</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/PQbuyKUaKFo&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/PQbuyKUaKFo&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-145175717272873143?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/145175717272873143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=145175717272873143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/145175717272873143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/145175717272873143'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/06/nerdy-but-funny.html' title='nerdy but funny'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-5331877391369232714</id><published>2009-06-07T17:53:00.002+02:00</published><updated>2009-06-07T17:53:57.338+02:00</updated><title type='text'>Ruby Toolbox</title><content type='html'>Just found this site (via a tweet)... seems to have a  comprehensive list of rails extensions, broken down by category.&lt;br /&gt;If only they linked to them!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ruby-toolbox.com/"&gt;Ruby Toolbox&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-5331877391369232714?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/5331877391369232714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=5331877391369232714' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5331877391369232714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5331877391369232714'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/06/ruby-toolbox.html' title='Ruby Toolbox'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3335294507421309941</id><published>2009-06-06T19:29:00.001+02:00</published><updated>2009-06-06T19:31:53.450+02:00</updated><title type='text'>Google's Page Speed</title><content type='html'>Google releases Page Speed - &lt;a href="http://tinyurl.com/mr66m9"&gt;get it here&lt;/a&gt; - an open-source Firefox plugin similar to Yahoo's YSlow&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3335294507421309941?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3335294507421309941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3335294507421309941' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3335294507421309941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3335294507421309941'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/06/googles-page-speed.html' title='Google&apos;s Page Speed'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6449121145179446195</id><published>2009-06-06T13:55:00.003+02:00</published><updated>2009-06-06T13:58:57.926+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='i18n'/><category scheme='http://www.blogger.com/atom/ns#' term='translations'/><category scheme='http://www.blogger.com/atom/ns#' term='222'/><title type='text'>i18n</title><content type='html'>We've (finally!) moved FilmAmora up to rails 2.2.2 - and not without some headaches.&lt;br /&gt;The biggest ones seem to revolve around translations. We were using po/mo files and that worked great. Moving to 222 required some changing of gems (to fastgettext) and other things. But we were left without standard translations of all the ruby messages for some reason.&lt;br /&gt;&lt;br /&gt;The guys at &lt;a href="http://rails-i18n.org"&gt;rails i18n.org&lt;/a&gt; came to the rescue!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tinyurl.com/8vj6a6"&gt;Their Github project&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Has config files for most locales that will cover all the standard messages. A real life saver!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6449121145179446195?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6449121145179446195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6449121145179446195' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6449121145179446195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6449121145179446195'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/06/i18n.html' title='i18n'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-220619502712087983</id><published>2009-05-24T20:17:00.001+02:00</published><updated>2009-05-24T20:19:31.870+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='leopard'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><title type='text'>installing the mysql gem under leopard</title><content type='html'>I am building a new dev laptop (an MSI Wind u100 running Leopard!) and got everything going... but getting the mysql gem to install was tricky. I had installed MySQL from a binary DMG install.&lt;br /&gt;The trick was to install the gem like so:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-220619502712087983?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/220619502712087983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=220619502712087983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/220619502712087983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/220619502712087983'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/05/installing-mysql-gem-under-leopard.html' title='installing the mysql gem under leopard'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6400629492523573861</id><published>2009-05-24T16:15:00.002+02:00</published><updated>2009-05-24T16:18:19.034+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>Forcing a different render format</title><content type='html'>I am writing an OAuth system for FilmAmora for the iphone app (and anything else I guess) to use.&lt;br /&gt;I want to always output xml from the controller that is handling the catalog output... but how to do that!&lt;br /&gt;&lt;br /&gt;I came up with this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def list&lt;br /&gt;    render :template =&amp;gt; &amp;quot;/catalogs/list.xml.builder&amp;quot;, :content_type =&amp;gt; &amp;quot;text/xml&amp;quot;&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will always output xml (with the right mime type) no matter what the requested format was.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6400629492523573861?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6400629492523573861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6400629492523573861' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6400629492523573861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6400629492523573861'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/05/forcing-different-render-format.html' title='Forcing a different render format'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3590557052375858570</id><published>2009-05-18T17:55:00.001+02:00</published><updated>2009-05-18T17:56:50.196+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Creating a new rails app with an old version</title><content type='html'>After much hunting I found how to do this&lt;br /&gt;&lt;br /&gt;gem list rails&lt;br /&gt;&lt;br /&gt;to see what versions you have. I need to create a 2.1.2 rails app. you can do that by issueing this command:&lt;br /&gt;&lt;br /&gt;rails _2.1.2_ my_app&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3590557052375858570?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3590557052375858570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3590557052375858570' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3590557052375858570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3590557052375858570'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/05/creating-new-rails-app-with-old-version.html' title='Creating a new rails app with an old version'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-8077191831854009389</id><published>2009-05-10T15:09:00.003+02:00</published><updated>2009-05-10T15:27:08.211+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cookies'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='subdomains'/><title type='text'>cookies and hosts / domains</title><content type='html'>I have been struggling for weeks with a problem of users being logged in to mysite.com, but not en.mysite.com and es.mysite.com. I posted on Ruby Groups and even tried to hire someone to do the work... but to no avail.&lt;br /&gt;Finally I think I cracked it today.&lt;br /&gt;&lt;br /&gt;Two things. First, for some reason doing this didn't work:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  if RAILS_ENV == 'production'&lt;br /&gt;    config.action_controller.session = {&lt;br /&gt;      :session_key =&amp;gt; '_my_session',&lt;br /&gt;      :session_domain =&amp;gt; '.mysite.com',&lt;br /&gt;      :secret      =&amp;gt; 'xxx'&lt;br /&gt;    }&lt;br /&gt;  else&lt;br /&gt;    config.action_controller.session = {&lt;br /&gt;      :session_key =&amp;gt; '_my_session',&lt;br /&gt;      :session_domain =&amp;gt; '.mysite.local',&lt;br /&gt;     :secret      =&amp;gt; 'xxy'&lt;br /&gt;    }&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, I substituted this into each environment file:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;config.after_initialize do&lt;br /&gt;  ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain] = '.mysite.local'&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That got my session's having the correct domain set (.mysite.com) meaning that the session was saved across subdomains.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cookies&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;But then I encountered a second problem. Cookies.&lt;br /&gt;After switching to hide and seek / show and tell methods to enable me to page cache even pages that had logged in status all over them (more on this in another post) I needed some user info in a cookie. But my cookies were tied to the subdomain!&lt;br /&gt;I was setting the cookies like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;      cookies[:current_user] = {&lt;br /&gt;        :cart_items_count =&amp;gt; cart_items_count,&lt;br /&gt;        :nothing =&amp;gt; 1&lt;br /&gt;      }.to_json&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I thought, ok I just need to add the domain in:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;      cookies[:current_user] = {&lt;br /&gt;        :cart_items_count =&amp;gt; cart_items_count,&lt;br /&gt;        :nothing =&amp;gt; 1,&lt;br /&gt;        :domain =&amp;gt; ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]&lt;br /&gt;      }.to_json&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;No...this didn't work. Everything was being chucked into the cookies 'value' and not the domain field (same happened if I added in an expires_at key). What was going on?&lt;br /&gt;Aha! It is the json-izing.&lt;br /&gt;&lt;br /&gt;So, I moved that out to a seperate variable:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;      value = {:cart_items_count =&amp;gt; cart_items_count, :nothing =&amp;gt; 1}.to_json&lt;br /&gt;      cookies.delete :login, :domain =&amp;gt; ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]&lt;br /&gt;      cookies[:current_user] = {&lt;br /&gt;        :value =&amp;gt; value,&lt;br /&gt;        :domain =&amp;gt; ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]&lt;br /&gt;      }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now my cookies had the proper domain info and the value was still proper json. And now my users are logged in across sub domains!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-8077191831854009389?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/8077191831854009389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=8077191831854009389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8077191831854009389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8077191831854009389'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/05/cookies-and-hosts-domains.html' title='cookies and hosts / domains'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2034945508334654942</id><published>2009-03-21T13:19:00.003+01:00</published><updated>2009-03-21T13:24:06.826+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='backgroundrb'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>backgroundrb by hostname</title><content type='html'>I love &lt;a href="http://backgroundrb.rubyforge.org/"&gt;backgroundrb&lt;/a&gt; - the way to run scheduled tasks and async workers. BUT on my setup I wanted to run certain backgroundrb tasks on one machine and certain ones on another (for memory reasons and also for testing).&lt;br /&gt;&lt;br /&gt;I couldn't find something that did that so I forked backgroundrb into my own repository on GitHub. You can find it &lt;a href="http://github.com/philsmy/backgroundrb/tree/master"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You can now have a config file like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;# A Sample YAML configuration file&lt;br /&gt;---&lt;br /&gt;:backgroundrb:&lt;br /&gt;  :ip: 0.0.0.0 #ip on which backgroundrb server is running&lt;br /&gt;  :port: 11006 #port on which backgroundrb server is running&lt;br /&gt;  :environment: production # rails environment loaded, defaults to development&lt;br /&gt;  :debug_log: true # whether to print debug logs to a seperate worker, defaults to true&lt;br /&gt;  :log: foreground # will print log messages to STDOUT, defaults to seperate log worker&lt;br /&gt;  # :result_storage: memcache # store results in a mecache cluster, you also need to specify location of your memcache clusters in next section&lt;br /&gt;  :persistent_disabled: true # turn this off if your application doesn't use backgroundrb's persistent/enqueued tasks system&lt;br /&gt;  :persistent_delay: 10 # the time (seconds) between each time backgroundrb checks the database for enqueued tasks&lt;br /&gt;  :per_environment: true&lt;br /&gt;&lt;br /&gt;# You specify your worker schedules here&lt;br /&gt;:whatever.local:&lt;br /&gt;    :backgroundrb: &lt;br /&gt;        :environment: test&lt;br /&gt;    :schedules:&lt;br /&gt;      :test_worker: # worker name&lt;br /&gt;        :test: #worker method&lt;br /&gt;          :trigger_args: */5 * * * * * * #worker schedule&lt;br /&gt;          :data: whatever&lt;br /&gt;&lt;br /&gt;:phils-mac-pro.local:&lt;br /&gt;    :backgroundrb: &lt;br /&gt;        :environment: development&lt;br /&gt;    :schedules:&lt;br /&gt;      :test_worker: # worker name&lt;br /&gt;        :test: #worker method&lt;br /&gt;          :trigger_args: */5 * * * * * * #worker schedule&lt;br /&gt;          :data: phil&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can launch backgroundrb with a specific hostname like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;./script/backgroundrb --hostname=whatever.local&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've created Capistrano tasks that fire up an instance on 2 servers and now they act differently based on hostname.&lt;br /&gt;&lt;br /&gt;Sweet!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2034945508334654942?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2034945508334654942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2034945508334654942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2034945508334654942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2034945508334654942'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/03/backgroundrb-by-hostname.html' title='backgroundrb by hostname'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-9013378189666153679</id><published>2009-03-13T16:23:00.002+01:00</published><updated>2009-03-13T16:26:07.931+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='sitemaps'/><title type='text'>Generating sitemaps and xml catalogues</title><content type='html'>One of the things we have to do at FilmAmora is generate a catalogue of our films. This is used in a few ways, but principally to drive our recommendations system.&lt;br /&gt;&lt;br /&gt;I stumbled across this great blog entry:&lt;br /&gt;&lt;a href="http://www.fortytwo.gr/blog/19/Generating-Sitemaps-With-Rails"&gt;Generating-Sitemaps-With-Rails&lt;/a&gt; that not only tells you a very nice way of generating sitemaps but also gave us great ideas for using the same technique to generate our catalogues.&lt;br /&gt;&lt;br /&gt;Awesome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-9013378189666153679?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/9013378189666153679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=9013378189666153679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9013378189666153679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9013378189666153679'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/03/generating-sitemaps-and-xml-catalogues.html' title='Generating sitemaps and xml catalogues'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-8538592988446668164</id><published>2009-02-13T20:39:00.003+01:00</published><updated>2009-02-13T20:54:57.846+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='europe'/><category scheme='http://www.blogger.com/atom/ns#' term='ec2onrails'/><category scheme='http://www.blogger.com/atom/ns#' term='amazon'/><title type='text'>ec2onrails EU</title><content type='html'>Well, necessity is the mother of invention. We needed new FilmAmora servers to deal with the increasing load. I also wanted to move to EU-based EC2 instances.&lt;br /&gt;That meant rolling our own because I believe there are no publicly available ec2onrails instances that run in the eu-west region.&lt;br /&gt;&lt;br /&gt;This was not as easy as I would have liked, so here's a little step by step.&lt;br /&gt;&lt;br /&gt;1. Go to &lt;a href="http://alestic.com/"&gt;Alestic&lt;/a&gt; and get the id of the proper eu instance. (At this writing it is ami-ac032bd8)&lt;br /&gt;&lt;br /&gt;2. Fire up an instance of this. I use Elastic Fox and you need to set the region to europe then choose this instance.&lt;br /&gt;&lt;br /&gt;3. copy your pem's into the instance: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;scp -i IDENTITY {cert,pk}-*.pem root@HOSTNAME:/mnt/&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;4. ssh into the instance&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;ssh -i IDENTITY root@HOSTNAME&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;5. Get the build script&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;wget http://ec2ubuntu-build-ami.notlong.com&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;6. update so you can get git&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get upgrade -y&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;7. get git&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;apt-get install git-core&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;8. get ec2onrails and use the latest branch&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;git clone git://github.com/pauldowman/ec2onrails.git&lt;br /&gt;cd ec2onrails&lt;br /&gt;git checkout --track -b 0.9.9.1 origin/0.9.9.1&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;9. Run the build script!&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt; bash ec2ubuntu-build-ami \&lt;br /&gt; --script /root/ec2onrails/server/build-ec2onrails.sh \&lt;br /&gt; --user YOUR_ACCOUNT_NUMBER \&lt;br /&gt; --access-key YOUR_ACCESS_KEY \&lt;br /&gt; --secret-key YOUR_SECRET_KEY \&lt;br /&gt; --bucket BUKCET_NAME \&lt;br /&gt; --prefix PREFIX \&lt;br /&gt; --location EU&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Your account number is the 12 digit number from your amazon access information page.&lt;br /&gt;&lt;br /&gt;10. Register the instance&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;ec2-register bucket/manifest.xml --region eu-west-1&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it!&lt;br /&gt;You should now be able to go to Elastic Fox and launch and instance of this that will be in Europe!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-8538592988446668164?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/8538592988446668164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=8538592988446668164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8538592988446668164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8538592988446668164'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/02/ec2onrails-eu.html' title='ec2onrails EU'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6127761204322494679</id><published>2009-02-11T13:12:00.001+01:00</published><updated>2009-02-11T13:15:08.855+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><category scheme='http://www.blogger.com/atom/ns#' term='blueprintcss'/><title type='text'>DropDown menu for Blueprint tabbed menus</title><content type='html'>I love &lt;a href="http://blueprintcss.org/"&gt;blueprint css&lt;/a&gt;! And I also love the &lt;a href="http://github.com/Montoya/blueprint-plugin---tabs/tree/master"&gt;tabs menu plugin&lt;/a&gt; for it. But, we neede drop down menus on FilmAmora. So I wrote a little extension that gives you that. It's not perfect, but, it works for now.&lt;br /&gt;&lt;br /&gt;Find it here:&lt;br /&gt;&lt;a href="http://github.com/philsmy/blueprint_dd/tree/master"&gt;Blueprint_dd&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6127761204322494679?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6127761204322494679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6127761204322494679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6127761204322494679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6127761204322494679'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/02/dropdown-menu-for-blueprint-tabbed.html' title='DropDown menu for Blueprint tabbed menus'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3988730356614465280</id><published>2009-02-06T12:05:00.002+01:00</published><updated>2009-02-06T12:12:01.986+01:00</updated><title type='text'>BackgroundRb and Synchronous calls</title><content type='html'>BackgroundRb lets you also call the workers synchronously. This is quite neat as you can use it as a form of pseudo-proxy and all other kinds of goodies.&lt;br /&gt;But, the documentation is lacking, so I am posting this for all you frustrated Googlers out there. Here is what you need to do.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class SampleWorker &amp;lt; BackgrounDRb::MetaWorker&lt;br /&gt;  set_worker_name :sample_worker&lt;br /&gt;&lt;br /&gt;  def create(args = nil)&lt;br /&gt;    # this method is called, when worker is loaded for the first time&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def test_me args&lt;br /&gt;    puts &amp;quot;test_me 1 (puts)&amp;quot;&lt;br /&gt;    logger.debug(&amp;quot;test_me hit (log)&amp;quot;)&lt;br /&gt;    return &amp;quot;of course it works&amp;quot;&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, the BackgroundRb site tells you to call this like so to get a response back:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;MiddleMan.worker(:sample_worker).test_me(:arg =&amp;gt; &amp;quot;1&amp;quot;)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This, in fact, won't work.&lt;br /&gt;&lt;br /&gt;You need to do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;MiddleMan.worker(:sample_worker).test_me({:arg =&amp;gt; &amp;quot;1&amp;quot;}, true)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The second parameter (and make sure you put {} around your first set of args) is some freaky boolean to say, "no, seriously, I want a result back". Otherwise you get nil.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Bonus Tip!&lt;/span&gt;&lt;br /&gt;When you define a method in a worker it HAS to accept arguments.&lt;br /&gt;This won't work:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def test_me&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def test_me(something = 1)&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3988730356614465280?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3988730356614465280/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3988730356614465280' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3988730356614465280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3988730356614465280'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/02/backgroundrb-and-synchronous-calls.html' title='BackgroundRb and Synchronous calls'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4352720518711116650</id><published>2009-01-16T20:28:00.001+01:00</published><updated>2009-01-16T20:29:50.205+01:00</updated><title type='text'>Rails and eTags</title><content type='html'>In the never ending search for speed I've been doing a lot of stuff with 304 Conditional get's. Here is a good article about etags - which is a vital component to it!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.tbray.org/ongoing/When/200x/2008/08/14/Rails-ETags"&gt;Rails-ETags&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4352720518711116650?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4352720518711116650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4352720518711116650' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4352720518711116650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4352720518711116650'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2009/01/rails-and-etags.html' title='Rails and eTags'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1593642658401717509</id><published>2008-12-12T17:19:00.003+01:00</published><updated>2009-05-24T21:08:38.648+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='leopard'/><title type='text'>MySQL and Leopard</title><content type='html'>I had such problems on my macbook (though not on the macpro) in getting mysql running.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://unlettered.org/2007/11/14/installing-mysql-50-on-mac-os-x-105-client/"&gt;This article &lt;/a&gt;seems to have helped.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1593642658401717509?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1593642658401717509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1593642658401717509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1593642658401717509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1593642658401717509'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/12/mysql-and-leopard.html' title='MySQL and Leopard'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2011947349661514812</id><published>2008-12-08T13:00:00.002+01:00</published><updated>2008-12-08T13:06:34.873+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='checkboxes'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>checkboxes for multiple items</title><content type='html'>I am doing an interface where I want to list a bunch of things (index) and have a checkbox next to each of them. Then, using a button, edit or show all those selected items.&lt;br /&gt;I am always running into this problem of checkboxes (maybe I am just stupid) so I spent some time and figured out a way that works for me. There are probably other solutions, but here is what I do:&lt;br /&gt;&lt;br /&gt;First, in the index.html I have this javascript code:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;% content_for :javascript do %&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;/* &amp;lt;![CDATA[ */&lt;br /&gt;    function editDevices() {&lt;br /&gt;        var device_count = document.getElementsByName('device[]').length; &lt;br /&gt;        var total=&amp;quot;&amp;quot;;&lt;br /&gt;        for(var i=0; i &amp;lt; device_count; i++){&lt;br /&gt;            if(document.forms['group_edit'].elements['device[]'][i].checked) {&lt;br /&gt;                if (total.length &amp;gt; 0) {&lt;br /&gt;                    total += &amp;quot;,&amp;quot;&lt;br /&gt;                }&lt;br /&gt;                total +=document.forms['group_edit'].elements['device[]'][i].value;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        new Ajax.Request('&amp;lt;%= group_edit_devices_path %&amp;gt;', { &lt;br /&gt;            parameters: { &lt;br /&gt;                authenticity_token: encodeURIComponent('&amp;lt;%=form_authenticity_token%&amp;gt;'),&lt;br /&gt;                device_ids: total&lt;br /&gt;            } &lt;br /&gt;        } &lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    function showDevices() {&lt;br /&gt;        var device_count = document.getElementsByName('device[]').length; &lt;br /&gt;        var total=&amp;quot;&amp;quot;;&lt;br /&gt;        for(var i=0; i &amp;lt; device_count; i++){&lt;br /&gt;            if(document.forms['group_edit'].elements['device[]'][i].checked) {&lt;br /&gt;                if (total.length &amp;gt; 0) {&lt;br /&gt;                    total += &amp;quot;,&amp;quot;&lt;br /&gt;                }&lt;br /&gt;                total +=document.forms['group_edit'].elements['device[]'][i].value;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        new Ajax.Request('&amp;lt;%= group_show_devices_path %&amp;gt;', { &lt;br /&gt;            parameters: { &lt;br /&gt;                authenticity_token: encodeURIComponent('&amp;lt;%=form_authenticity_token%&amp;gt;'),&lt;br /&gt;                device_ids: total&lt;br /&gt;            } &lt;br /&gt;        } &lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;    /* ]]&amp;gt; */&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then I have the table of devices:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;table border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;thead&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;&amp;amp;nbsp;&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Uid&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Ip&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;# Displays&amp;lt;/th&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;/thead&amp;gt;&lt;br /&gt;        &amp;lt;tfoot&amp;gt;&lt;br /&gt;            &amp;lt;tr&amp;gt;&lt;br /&gt;                &amp;lt;td colspan=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;                    &amp;lt;ul class=&amp;quot;tabs&amp;quot;&amp;gt;&lt;br /&gt;                        &amp;lt;li&amp;gt;&amp;lt;%= link_to_function &amp;quot;Show&amp;quot;, &amp;quot;showDevices()&amp;quot;  %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;                        &amp;lt;li&amp;gt;&amp;lt;%= link_to_function &amp;quot;Edit&amp;quot;, &amp;quot;editDevices()&amp;quot; %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;                        &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Delete&amp;quot; %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;                    &amp;lt;/ul&amp;gt;&lt;br /&gt;                &amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;/tfoot&amp;gt;&lt;br /&gt;        &amp;lt;tbody&amp;gt;&lt;br /&gt;            &amp;lt;% for device in @devices %&amp;gt;&lt;br /&gt;            &amp;lt;tr&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;%= check_box_tag(&amp;quot;device[]&amp;quot;, device.id, false, :id =&amp;gt; &amp;quot;device_#{device.id}&amp;quot;) %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;%=link_to_remote h(device.uid), :url =&amp;gt; formatted_device_path(device, :js), :method =&amp;gt; &amp;quot;get&amp;quot; %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;%=h device.name %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;%=h device.ip %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;%= device.displays.count %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;/tr&amp;gt;&lt;br /&gt;            &amp;lt;% end %&amp;gt;&lt;br /&gt;        &amp;lt;/tbody&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The result is that my ajax function will be called with a comma separated list of the ids of the selected devices.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2011947349661514812?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2011947349661514812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2011947349661514812' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2011947349661514812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2011947349661514812'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/12/checkboxes-for-multiple-items.html' title='checkboxes for multiple items'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-5834803172671089694</id><published>2008-11-27T12:33:00.002+01:00</published><updated>2008-11-27T12:38:32.932+01:00</updated><title type='text'>&amp;@$%^£&amp; IE 7 and insecure content!</title><content type='html'>What a morning!&lt;br /&gt;&lt;br /&gt;A user kindly reported that he couldn't log in to FilmAmora using IE7. IE6 worked, FireFox worked. Safari worked.&lt;br /&gt;&lt;br /&gt;IE7 (for me) was coming up first with the 'there is insecure content on this page do you wish to show it?' (the login in page is under https). Clicking yes or no had the same result: the page would flash but then IE7 reported that it couldn't show the page. (It should have, it turns out, said 'I am choosing not to show the page').&lt;br /&gt;&lt;br /&gt;The issue was that insecure content. For me, specifically it was the statcounter call. But your issue may be other calls. Anyway, I removed all calls to anything outside of my domain and that seems to have fixed it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-5834803172671089694?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/5834803172671089694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=5834803172671089694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5834803172671089694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5834803172671089694'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/11/ie-7-and-insecure-content.html' title='&amp;@$%^£&amp; IE 7 and insecure content!'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-7991908556856248647</id><published>2008-11-03T11:56:00.001+01:00</published><updated>2008-11-03T11:58:22.655+01:00</updated><title type='text'>unfuddle</title><content type='html'>I use unfuddle as a git host and bug tracking, etc service. But, because I have so many projects on the go I ran into this problem where you can only have an ssh key in ONE account on unfuddle. So, I wrote to the support guys and asked them how to handle multiple accounts from one machine.&lt;br /&gt;Here is their response:&lt;br /&gt;&lt;br /&gt;The easiest way to deal with need multiple keys for multiple accounts is to actually just create them using different filenames in your ~/.ssh/ directory.  For instance, if you have 2 accounts, "account1" and "account2", you would want to run "ssh-keygen -t rsa" twice, each time specifying a different filename:&lt;br /&gt;&lt;br /&gt;~/.ssh/unfuddle_account1_id_rsa&lt;br /&gt;~/.ssh/unfuddle_account2_id_rsa&lt;br /&gt;&lt;br /&gt;Now, by default, ssh will use the file ~/.ssh/id_rsa when connecting to a remote server.  As neither of your keys is in this file, you must tell SSH (not git) which private keyfile to use when connecting to each account.  This is done using the SSH config file.&lt;br /&gt;&lt;br /&gt;For instance, create or edit a file named .ssh/config with the following contents:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Host account1.unfuddle.com&lt;br /&gt;  User git&lt;br /&gt;  IdentityFile ~/.ssh/unfuddle_account1_id_rsa&lt;br /&gt;&lt;br /&gt;Host account2.unfuddle.com&lt;br /&gt;  User git&lt;br /&gt;  IdentityFile ~/.ssh/unfuddle_account2_id_rsa&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have followed this model for my own accounts (of which I have many) and it has worked perfectly.  I hope this helps you as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-7991908556856248647?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/7991908556856248647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=7991908556856248647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7991908556856248647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7991908556856248647'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/11/unfuddle.html' title='unfuddle'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4402331619963357210</id><published>2008-10-16T19:00:00.002+02:00</published><updated>2008-10-16T19:02:20.090+02:00</updated><title type='text'>Creating a summary</title><content type='html'>I have an app that has rows of statistics. We wanted to create summaries of arbitrary rows.&lt;br /&gt;This method seems to work:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def self.create_summary_row(array)&lt;br /&gt;    unless array.blank?&lt;br /&gt;      klazz = array.first.class&lt;br /&gt;      sum_stat = klazz.new&lt;br /&gt;      array.each do &amp;#124;line&amp;#124;&lt;br /&gt;        if line.is_a?(klazz)&lt;br /&gt;          line.attributes.each do &amp;#124;k,v&amp;#124;&lt;br /&gt;            unless v.nil? &amp;#124;&amp;#124; v.is_a?(Time) &amp;#124;&amp;#124; v.is_a?(Date)&lt;br /&gt;              if sum_stat[k].nil?&lt;br /&gt;                sum_stat[k] = v &lt;br /&gt;              else&lt;br /&gt;                sum_stat[k] += v&lt;br /&gt;              end &lt;br /&gt;            end&lt;br /&gt;          end&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;      sum_stat&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4402331619963357210?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4402331619963357210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4402331619963357210' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4402331619963357210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4402331619963357210'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/10/creating-summary.html' title='Creating a summary'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-8363997793438432681</id><published>2008-09-29T18:56:00.004+02:00</published><updated>2008-09-29T19:01:31.772+02:00</updated><title type='text'>ec2onrails</title><content type='html'>This is so great - goodbye other hosting companies that can't compete!&lt;br /&gt;&lt;br /&gt;Amazon has hosting facilities known as ec2 (elastic compute cloud). You pay by the hour ($.10 for a small installation). That works out to around $70/month. But, the power you get is much better than your average hosting.&lt;br /&gt;&lt;br /&gt;Paul Dowman has released a great ec2 instance called &lt;a href="http://ec2onrails.rubyforge.org/"&gt;ec2onrails&lt;/a&gt; that can get your rails app up and running on ec2 in about 30 minutes. I am now using it for FilmAmora as well as for another client.&lt;br /&gt;&lt;br /&gt;It is awesome!&lt;br /&gt;&lt;br /&gt;One thing I discovered today was the sweet built-in support for cron jobs. Write a script and plop it in your app's script directory. Call it hourly, daily or weekly (perhaps monthly? I didn't check). This script will get run automatically by an already existing cron job! No need to figure out those silly cron settings. Very cool!&lt;br /&gt;&lt;br /&gt;I highly recommend it. FilmAmora is running much much better on it than on the old hosting (where I had to restart it every day just to hopefully have enough memory to run 2 mongrels).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-8363997793438432681?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/8363997793438432681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=8363997793438432681' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8363997793438432681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/8363997793438432681'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/09/ec2onrails.html' title='ec2onrails'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-6214883896385595745</id><published>2008-08-15T09:52:00.002+02:00</published><updated>2008-08-15T09:56:30.007+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='secure forms'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><title type='text'>secure forms</title><content type='html'>One thing I struggled with in RoR was creating forms that submitted to https. So I ended up writing a couple of helpers:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def secure_form_for(record_or_name_or_array, *args, &amp;amp;proc)&lt;br /&gt;    unless RAILS_ENV == 'production'&lt;br /&gt;      url_options = {}&lt;br /&gt;    else&lt;br /&gt;      url_options = {:protocol =&amp;gt; 'https://', :only_path =&amp;gt; false }&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    options = args.last.is_a?(Hash) ? args.pop : {}&lt;br /&gt;    if !options[:url].nil?&lt;br /&gt;      options[:url] = url_options.merge options[:url]&lt;br /&gt;    else&lt;br /&gt;      options[:url] = url_options&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    return form_for(record_or_name_or_array, options, &amp;amp;proc)&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def secure_form_tag(*args, &amp;amp;proc)&lt;br /&gt;    logger.debug(&amp;quot;secure_form_tag args #{args.inspect}&amp;quot;)&lt;br /&gt;    unless RAILS_ENV == 'production'&lt;br /&gt;      url_options = {}&lt;br /&gt;    else&lt;br /&gt;      url_options = {:protocol =&amp;gt; 'https://', :only_path =&amp;gt; false }&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    options = args.last.is_a?(Hash) ? args.pop : {}&lt;br /&gt;    if !options[:url].nil?&lt;br /&gt;      options[:url] = url_options.merge options[:url]&lt;br /&gt;    else&lt;br /&gt;      options[:url] = url_options&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    logger.debug(&amp;quot;secure_form_tag options #{options.inspect}&amp;quot;)&lt;br /&gt;&lt;br /&gt;    return form_tag(options, &amp;amp;proc)&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The should be simple replacements for form_for and form_tag. Now, I have to admit I wrote these when I was using Rails 1.2.5, so there might be some things in 2.x that make these redundant, but, they work for me.&lt;br /&gt;The only caveat is that if you are doing a form where you are not passing in the action, just the object e.g &lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;% form_for @object do %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you are going to have to supply the actions. I am looking into this now, and I might rewrite this post if I sort it out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-6214883896385595745?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/6214883896385595745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=6214883896385595745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6214883896385595745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/6214883896385595745'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/08/secure-forms.html' title='secure forms'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2948113895745166307</id><published>2008-07-26T15:08:00.003+02:00</published><updated>2008-07-28T11:07:55.850+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='xml_hidden'/><title type='text'>xml_hidden plugin</title><content type='html'>Recently I've been investigating the steps needed to open up FilmAmora's API to the outside world. That means supplying xml data so people can do what they want with it.&lt;br /&gt;But I didn't want sensitive data in models to be exposed in the xml. And I also am too lazy to write custom to_xml methods for everything.&lt;br /&gt;&lt;br /&gt;So I wrote a plugin call &lt;a href="http://github.com/philsmy/xml_hidden/tree"&gt;xml_hidden&lt;/a&gt; That lets you set something on the class to hide certain attributes from xml output.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Film &amp;lt; ActiveRecord::Base&lt;br /&gt;  attr_xml_hidden :acquiring_url, :id, :created_at&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now whenever I output a film to xml those values can't be seen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2948113895745166307?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2948113895745166307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2948113895745166307' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2948113895745166307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2948113895745166307'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/07/xmlhidden-plugin.html' title='xml_hidden plugin'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4291258805687177085</id><published>2008-07-20T10:30:00.001+02:00</published><updated>2008-07-20T10:35:24.766+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='erb'/><title type='text'>Escaping for JavaScript</title><content type='html'>Recently I've started to use the most excellent &lt;a href="http://www.nickstakenburg.com/projects/prototip2/"&gt;Prototip2&lt;/a&gt; for doing sexy tooltip stuff. It works a treat.&lt;br /&gt;The only problem I have had is that some of the things I want to put into the tips have single quotes in them (e.g Bob's Team). I was surprised to find that Rails doesn't (as far as I could find) have a handy dandy way of making strings JS friendly. So I whipped up this extention to Erb::Util.&lt;br /&gt;I hope some of you find it useful. It will escape single quotes and as an added bonus it also does the html escaping so you only have to make one call.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class ERB&lt;br /&gt;  module Util&lt;br /&gt;    def js_escape(str)&lt;br /&gt;      h(str.gsub(/[']/, '\\\\\''))&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    alias js js_escape&lt;br /&gt;    module_function :js&lt;br /&gt;    module_function :js_escape&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I put this into an initializer.&lt;br /&gt;&lt;br /&gt;You can then call it from your views like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;%=js team.name%&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4291258805687177085?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4291258805687177085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4291258805687177085' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4291258805687177085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4291258805687177085'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/07/escaping-for-javascript.html' title='Escaping for JavaScript'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-358720020598372786</id><published>2008-07-14T13:01:00.001+02:00</published><updated>2008-07-14T14:51:36.048+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='xss'/><title type='text'>Combating XSS</title><content type='html'>This info is available elsewhere, but as I always forget, this is a good place to repeat it.&lt;br /&gt;&lt;br /&gt;Install the White List plugin. Get it &lt;a href="http://weblog.techno-weenie.net/2006/9/3/white-listing-plugin-for-rails"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Once installed you'll need to add the following line to the init.rb of the white_list plugin:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;ActionView::Base.send :include, WhiteListHelper&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the Application.rb (Application Controller)&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;include HtmlFilterHelper&lt;br /&gt;before_filter :sanitize_params&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then I have a class called HtmlFilterHelper&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;module HtmlFilterHelper&lt;br /&gt;  def sanitize_params(params = params)&lt;br /&gt;    params = walk_hash(params) if params&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;  def walk_hash(hash)&lt;br /&gt;    hash.keys.each do &amp;#124;key&amp;#124;&lt;br /&gt;      if hash[key].is_a? String&lt;br /&gt;        hash[key] = white_list(hash[key])&lt;br /&gt;      elsif hash[key].is_a? Hash&lt;br /&gt;        hash[key] = walk_hash(hash[key])&lt;br /&gt;      elsif hash[key].is_a? Array&lt;br /&gt;        hash[key] = walk_array(hash[key])&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    hash&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def walk_array(array)&lt;br /&gt;    array.each_with_index do &amp;#124;el,i&amp;#124;&lt;br /&gt;      if el.is_a? String&lt;br /&gt;        array[i] = white_list(el)&lt;br /&gt;      elsif el.is_a? Hash&lt;br /&gt;        array[i] = walk_hash(el)&lt;br /&gt;      elsif el.is_a? Array&lt;br /&gt;        array[i] = walk_array(el)&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    array&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For what it is worth, I also do stuff like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;%=white_list synopsis.synopsis[0,100].gsub(/&amp;lt;\/?[^&amp;gt;]*&amp;gt;/, &amp;quot;&amp;quot;)%&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which removes any html-style tags from the text and then white_list's it before outputting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-358720020598372786?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/358720020598372786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=358720020598372786' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/358720020598372786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/358720020598372786'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/07/combating-xss.html' title='Combating XSS'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1823449550877983577</id><published>2008-07-09T23:28:00.000+02:00</published><updated>2008-07-09T23:33:14.866+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Becoming a Git</title><content type='html'>Recently the SVN repository service we were using for FilmAmora had a lengthy outage. So, being a real Rails-er I decided to switch over to GitHub. Getting the source up into it was pretty easy.&lt;br /&gt;&lt;br /&gt;So, I went ahead and started making changes and doing git commit's and all that good stuff. Well, today I went to the projects homepage on GitHub and you can imagine my surprise and horror when I saw that it looked like nothing had been checked in since my original commit.&lt;br /&gt;&lt;br /&gt;Wot de hell?!&lt;br /&gt;&lt;br /&gt;I then scoured the net for Git for dummies without success. So here it is:&lt;br /&gt;&lt;br /&gt;1) Do all the stuff they tell you do to to get your code in.&lt;br /&gt;2) Do your commits... but remember that for some strange reason you are committing into your LOCAL Git repository.&lt;br /&gt;3) here's the key - do a git push! that will chuck your code up onto the server.&lt;br /&gt;&lt;br /&gt;Seems perhaps obviously, but coming from an svn or cvs background it confused the hell out of me.&lt;br /&gt;At a later date (probably this weekend) I will write a little Git note about how this works from the perspective of someone used to using one of the more traditional source code systems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1823449550877983577?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1823449550877983577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1823449550877983577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1823449550877983577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1823449550877983577'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/07/becoming-git.html' title='Becoming a Git'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-836137576895318724</id><published>2008-07-05T11:51:00.000+02:00</published><updated>2008-07-05T12:00:53.724+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='encoding'/><title type='text'>Euro-friendly permalinks</title><content type='html'>&lt;a href="http://github.com/nakajima/permalink_fu/tree/master"&gt;Permalink_fu&lt;/a&gt; is rather an awesome thing. The only drawback is that it doesn't really handle accented characters very well. I've looked around and seen a bunch of solutions that attempt to be 'clever' and do the substitution on one line, etc. But I decided that I'd rather go for brute force.&lt;br /&gt;I created an extension to String with one method called 'no_accents':&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class String&lt;br /&gt;  def no_accents&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then I do a whack of these:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    str = self&lt;br /&gt;    #Spanish letters&lt;br /&gt;    str = str.gsub(&amp;quot;&amp;#225;&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;    str = str.gsub(&amp;quot;&amp;#233;&amp;quot;,&amp;quot;e&amp;quot;)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;For upper and lower case.&lt;br /&gt;Obviously there is a big list. Right now I am just doing Spanish, French and German as they are the ones I am most interested in.&lt;br /&gt;&lt;br /&gt;I had to make a change to Permalink_fu to call my method first:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    def escape(str)&lt;br /&gt;      str = str.no_accents&lt;br /&gt;      s = ((translation_to &amp;amp;&amp;amp; translation_from) ? Iconv.iconv(translation_to, translation_from, str) : str).to_s&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But that's all.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.costafilma.com/stuff/character_convert.rb"&gt;Here&lt;/a&gt; is the file. What I did is put it in my initializers directory.&lt;br /&gt;&lt;br /&gt;If you add to it maybe you could post your additions. I am sure some clever-clogs out there will come up with a more slick solution. But... mine works!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-836137576895318724?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/836137576895318724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=836137576895318724' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/836137576895318724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/836137576895318724'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/07/euro-friendly-permalinks.html' title='Euro-friendly permalinks'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-5057416914267795312</id><published>2008-06-28T13:10:00.000+02:00</published><updated>2008-06-28T13:38:31.199+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gettext'/><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='memcache'/><title type='text'>Rails 2.1 caching - nothing is ever easy!</title><content type='html'>Last night I watched the new &lt;a href="http://railscasts.com/episodes/115"&gt;Railscast episode&lt;/a&gt; that talked about the new caching features in Rails 2.1. I thought it looked cool and would add it to the new round of FilmAmora changes.&lt;br /&gt;&lt;br /&gt;But... nothing is every easy!&lt;br /&gt;&lt;br /&gt;I may look simple, but I encountered several problems&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Conflicts with GetText&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We use GetText for the translations on FilmAmora. We like it because there are free poEditor apps on every platform and we can easily send off the files to whomever to be translated.&lt;br /&gt;&lt;br /&gt;The problem comes with this line:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;require 'gettext/rails'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That you need to have to fire up some of the Rails-specific GetText stuff. This is all fine - it has been working for quite some time. But, when I tried to cache our Genres like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def self.all_cached(language)&lt;br /&gt;    key = &amp;quot;genres_#{language}&amp;quot;&lt;br /&gt;    Rails.cache.fetch(key) {Genre.find(:all).sort_by {&amp;#124;genre&amp;#124; genre.get_description}.reject {&amp;#124;g&amp;#124; g.get_films_count == 0}}&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is the result:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;undefined method `cache' for GetText::Rails:Module&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What?!?! Yes, it seems that GetText::Rails will hide Rails. This is, quite frankly, SHIT. So, after a long time poking around I have discovered that you need to do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def self.all_cached(language)&lt;br /&gt;    key = &amp;quot;genres_#{language}&amp;quot;&lt;br /&gt;    ::Rails.cache.fetch(key) {Genre.find(:all).sort_by {&amp;#124;genre&amp;#124; genre.get_description}.reject {&amp;#124;g&amp;#124; g.get_films_count == 0}}&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yippee! It will all work now, right?&lt;br /&gt;&lt;br /&gt;Wrong.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Class != Class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I hit refresh the first time and wow was I excited! I saw lines like this in the log:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Cache write (will save 0.59562): genres_es&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Woo hoo! Look at all the time I will save!&lt;br /&gt;&lt;br /&gt;So I hit refresh.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;undefined method `get_description' for #&amp;lt;Genre id: 1, description: &amp;quot;Action and Adventure&amp;quot;, order_by: 2&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What?!?!&lt;br /&gt;&lt;br /&gt;I am using the 'default' memory store. Something is going funny with retrieving objects from it. I &lt;span style="font-weight:bold;"&gt;never solved this problem&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If I do this in the console:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;gt;&amp;gt; @genres = Genre.all_cached(&amp;quot;es&amp;quot;)&lt;br /&gt;&amp;gt;&amp;gt; @genres = Genre.all_cached(&amp;quot;es&amp;quot;)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I see this in the log:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Cache write (will save 0.51974): genres_es&lt;br /&gt;Cache hit: genres_es ({})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And I can do this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;gt;&amp;gt; @genres[0].get_description(&amp;quot;es&amp;quot;)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So what is going on in my web app? I have no idea. It seems that the class retrieved from the memory cache is incomplete in some way. get_description is not an accessor, it does go off and get the translation, but... so what? it is still a method.&lt;br /&gt;This had me stumped!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. File Store no worky&lt;/span&gt;&lt;br /&gt;So I added this to development.rb:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;config.cache_store = :file_store, '/cache_store'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I ended up getting this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;undefined method `get_description' for #&amp;lt;String:0x5459f0c&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok, I am tired of this now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. MemCached&lt;/span&gt;&lt;br /&gt;Everyone is talking about using MemCached for this kind of thing. Now, I know developers and we are a lazy bunch. My guess is that this whole caching stuff has been written with MemCache in mind and screw anything else (see points 2 and 3 above).&lt;br /&gt;So I installed &lt;a href="http://www.silverchairsolutions.com/blog/?p=4"&gt;MemCache&lt;/a&gt; and changed the line in the development.rb to be this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;config.cache_store = :mem_cache_store&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I restarted the server and hit refresh. Trying to contain my excitement I saw a properly rendered page.&lt;br /&gt;I hit refresh again.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;undefined class/module Subgenre&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;For CHRIST'S SAKE!&lt;br /&gt;After another web-scouring exercise I discovered &lt;a href="http://blog.cbciweb.com/articles/2007/05/31/workaround-the-memcached-undefined-class-module-bug"&gt;a solution&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;My method now looks like this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def self.all_cached(language)&lt;br /&gt;    key = &amp;quot;genres_#{language}&amp;quot;&lt;br /&gt;    Subgenre&lt;br /&gt;    ::Rails.cache.fetch(key) {Genre.find(:all).sort_by {&amp;#124;genre&amp;#124; genre.get_description}.reject {&amp;#124;g&amp;#124; g.get_films_count == 0}}&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And guess what? It works. Of course it now means running memcache on my local machine and installing it on the production box. But I've saved .52 seconds! It took 3 hours to get to the solution, so I figure in only 350 web page hits I will make it back.&lt;br /&gt;&lt;br /&gt;Oh, of course I was already caching the html on the server for most things, but this is a little tidier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-5057416914267795312?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/5057416914267795312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=5057416914267795312' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5057416914267795312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/5057416914267795312'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/rails-21-caching-nothing-is-ever-easy.html' title='Rails 2.1 caching - nothing is ever easy!'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1609725536018237285</id><published>2008-06-27T09:27:00.000+02:00</published><updated>2008-06-27T09:31:52.809+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='offsite linking'/><category scheme='http://www.blogger.com/atom/ns#' term='link_to'/><title type='text'>Linking offsite</title><content type='html'>When you get into something like Ruby on Rails you want to use it for everything - the old adage about getting a hammer and everything becomes a nail rings true in programming!&lt;br /&gt;&lt;br /&gt;I wanted to link to Wikipedia. I thought I could use link_to for something like that, but it turns out that really link_to (and it's variations) are meant to link to something inside your RoR app, not outside of it.&lt;br /&gt;&lt;br /&gt;So I wrote this handy method that generates a link off to Wikipedia.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def wikipedia_link(text, language = current_language.to_s)&lt;br /&gt;  &amp;quot;&amp;lt;a href=\&amp;quot;http://www.wikipedia.org/search-redirect.php?search=#{h(text)}&amp;amp;amp;language=#{language}\&amp;quot; target=\&amp;quot;new\&amp;quot;&amp;gt;Wikipedia&amp;lt;/a&amp;gt;&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;It's fairly simple - pass in the text you want to find on Wikipedia and your language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1609725536018237285?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1609725536018237285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1609725536018237285' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1609725536018237285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1609725536018237285'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/linking-offsite.html' title='Linking offsite'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-7754161448172141043</id><published>2008-06-19T10:22:00.000+02:00</published><updated>2008-12-09T18:29:42.031+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='forms'/><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='ie6'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>IE and form spacing</title><content type='html'>One has to wonder how Microsoft got it so wrong, but anyway.&lt;br /&gt;&lt;br /&gt;One thing I love about RoR is the ajax side of it and how easy it makes it. For instance adding something to a cart with ajax:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;% form_remote_tag :url =&amp;gt; {:controller =&amp;gt; :store, :action =&amp;gt; :add_to_cart, :id =&amp;gt; film} do %&amp;gt;&lt;br /&gt;    &amp;lt;%=submit_tag(_('Buy &amp;amp;raquo;'), &amp;quot;title&amp;quot; =&amp;gt; _(&amp;quot;add to cart @ %s&amp;quot;) % number_to_currency(film.price, :unit =&amp;gt; &amp;quot;&amp;#8364;&amp;quot;), :class =&amp;gt; &amp;quot;buy_button_big buy_button&amp;quot;)%&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is great. On FireFox it looks like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iy2w4vyQwV0/SFoYwXoqL0I/AAAAAAAAADY/plIOgcOzetI/s1600-h/Picture+9.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_iy2w4vyQwV0/SFoYwXoqL0I/AAAAAAAAADY/plIOgcOzetI/s320/Picture+9.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5213506737892110146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But on IE6 it looks like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iy2w4vyQwV0/SFoZcoGbEwI/AAAAAAAAADo/k7C0ober5WE/s1600-h/Picture+10.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_iy2w4vyQwV0/SFoZcoGbEwI/AAAAAAAAADo/k7C0ober5WE/s320/Picture+10.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5213507498226160386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Insane quatities of extra space. Seems that IE loves to add space after forms. You can't stop it! &lt;br /&gt;&lt;br /&gt;Or can you!?&lt;br /&gt;&lt;br /&gt;I have found that adding this in my css is the trick:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;form {&lt;br /&gt;  margin:0;&lt;br /&gt;  padding:0;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But, since I don't need it in ff... why not use the very sweet &lt;a href="http://rafael.adm.br/css_browser_selector/"&gt;CSS Browser Selector plugin&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Now you can do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;.ie6 form {&lt;br /&gt;  margin:0;&lt;br /&gt;  padding:0;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Add all shall be well &lt;a href="http://www.filmamora.com/film/being_there"&gt;in the garden.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-7754161448172141043?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/7754161448172141043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=7754161448172141043' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7754161448172141043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7754161448172141043'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/ie-and-form-spacing.html' title='IE and form spacing'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iy2w4vyQwV0/SFoYwXoqL0I/AAAAAAAAADY/plIOgcOzetI/s72-c/Picture+9.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-9114998378308493952</id><published>2008-06-17T21:12:00.000+02:00</published><updated>2008-06-17T21:18:15.953+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><title type='text'>pull from another site</title><content type='html'>Recently a site I was working on needed to forward all unknown requests to another website (their old website). This turned out to be shockingly easy to do!&lt;br /&gt;&lt;br /&gt;In the Application Controller:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def default&lt;br /&gt;    logger.debug(&amp;quot;request.env[\&amp;quot;REQUEST_URI\&amp;quot;] #{request.env[&amp;quot;REQUEST_URI&amp;quot;]}&amp;quot;)&lt;br /&gt;    render :text =&amp;gt; Net::HTTP.get_response(&lt;br /&gt;      &amp;quot;www.oldsite.com&amp;quot;,&lt;br /&gt;      request.env[&amp;quot;REQUEST_URI&amp;quot;]&lt;br /&gt;      ).body&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And at the very bottom (so it is only done if nothing else catches the route):&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  map.connect '*path' , :controller =&amp;gt; 'application' , :action =&amp;gt; 'default'&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Easy peasy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-9114998378308493952?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/9114998378308493952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=9114998378308493952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9114998378308493952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/9114998378308493952'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/pull-from-another-site.html' title='pull from another site'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2842225863298942621</id><published>2008-06-14T13:10:00.000+02:00</published><updated>2008-06-14T13:10:15.971+02:00</updated><title type='text'>Format My Source Code for Blogging</title><content type='html'>&lt;a href="http://formatmysourcecode.blogspot.com/2006/02/paste-your-text-here.html#links"&gt;Format My Source Code for Blogging&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2842225863298942621?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://formatmysourcecode.blogspot.com/2006/02/paste-your-text-here.html#links' title='Format My Source Code for Blogging'/><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2842225863298942621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2842225863298942621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2842225863298942621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2842225863298942621'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/format-my-source-code-for-blogging.html' title='Format My Source Code for Blogging'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3234262719401990699</id><published>2008-06-14T09:39:00.000+02:00</published><updated>2008-06-29T15:41:32.227+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='views'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Absolving your views of responsibility</title><content type='html'>One thing I struggled with when I started out with RoR was how to create a site that was 'current looking'. In all the books they told you about views and layouts, but not how to use the layout to its most effective end.&lt;br /&gt;What I wanted was a simple 3 column website. But instead of 'static' information in the left and right column I wanted it to change. In some cases it was ads, in some cases a list of items, etc. The only thing I could think of was to hold a lot of layout information in the view. So, I would have the header and footer in layouts/application.html.erb but in the middle there was a big &lt;%= :yield %&gt; that would handle the middle (vertically) of the page, including the columns.&lt;br /&gt;(Hold on, I'm getting to the code!)&lt;br /&gt;The problem with this is that if your view is wrong, or if you don't include it, then your site goes all to hell.&lt;br /&gt;&lt;br /&gt;The solution, I found, was named :yields.&lt;br /&gt;&lt;br /&gt;To illustrate I am going to build a funky 3 column site in 5 minutes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Create the project&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ rails threecol&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To set up a new project&lt;br /&gt;&lt;br /&gt;Neat tip: open TextMate and drag the threecol folder onto the icon in the doc. That way it will open up the whole structure (i.e. the rails project).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Add a layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Matthew James Taylor has a great website with some free to use CSS templates. So, we're going to use his 3 column one.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://matthewjamestaylor.com/blog/perfect-3-column.htm"&gt;Go here&lt;/a&gt;. View source, copy the CSS.&lt;br /&gt;&lt;br /&gt;Create a new file in your public/stylesheets directory called site.css and paste the CSS from Matt's page in.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Include the CSS in your Layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create a file in your app/views/layouts directory called application.html.erb. This is the name for the default layout, so you don't need to change anything in the controller we'll create in a moment.&lt;br /&gt;&lt;br /&gt;Go back to &lt;a href="http://matthewjamestaylor.com/blog/perfect-3-column.htm"&gt;Matt's page&lt;/a&gt;, view source and paste the whole thing into application.html.erb. Delete the styles definitions from here. (lines 12 - 170 as of this writing)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Knock up a scaffold&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(Best to setup the database.yml here first)&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ script/generate scaffold product name:string description:string&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;note: in Rails 2 you don't have the same scaffolding as before. doing the above, where you define some fields, will give you a controller, model, views and migration&lt;br /&gt;&lt;br /&gt;Get everything setup:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ rake db:drop db:create db:migrate test&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Get your CSS on&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Delete products.html.erb from the layouts directory. For our example we don't need it.&lt;br /&gt;&lt;br /&gt;Back in your application.html.erb paste this line in the header:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;%= stylesheet_link_tag 'site' %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you start the server (script/server) now and go to localhost:3000/products you should see Matthew's page all nice and purty because we haven't included any of our content.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Get your content in&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Delete the center of Matthew's code (lines 40 - 59 here) and replace it with&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;%= :yield %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Refresh now and you will see your scaffold in the middle. Nice.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Sidebars&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ok, we could have done all that easy, so let's get to the fun stuff.&lt;br /&gt;Delete Matthew's code for either sidebar. &lt;br /&gt;The center of your application.html.erb should now look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;            &amp;lt;div class=&amp;quot;col1&amp;quot;&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;!-- Column 1 start --&amp;gt;&lt;br /&gt;                    &amp;lt;%= yield %&amp;gt;&lt;br /&gt;                &amp;lt;!-- Column 1 end --&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;            &amp;lt;div class=&amp;quot;col2&amp;quot;&amp;gt;&lt;br /&gt;                &amp;lt;!-- Column 2 start --&amp;gt;&lt;br /&gt;                &amp;lt;!-- Column 2 end --&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;            &amp;lt;div class=&amp;quot;col3&amp;quot;&amp;gt;&lt;br /&gt;                &amp;lt;!-- Column 3 start --&amp;gt;&lt;br /&gt;                &amp;lt;!-- Column 3 end --&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;inside column 2 (the left nav in Matthew's layout) put this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;%= yield :left_nav_content %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In views/products/index.html.erb do this:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;% content_for :left_nav_content do %&amp;gt;&lt;br /&gt;    &amp;lt;h1&amp;gt;Here it is!&amp;lt;/h1&amp;gt;&lt;br /&gt;    &amp;lt;div&amp;gt;Exciting left-nav content&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What is going on?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We all know about &lt;%= yield %&gt;, but adding a name to it says to look in your view (or any views including, even through partial rendering) and see if there is something that wants to write out to this space. &lt;% content_for :left_nav_content do %&gt; says that the stuff in here, please write there.&lt;br /&gt;&lt;br /&gt;The power is - you can do anything in there. Include partials, for instance.&lt;br /&gt;&lt;br /&gt;The advantage is that now you can not screw up your layout. You can still put things whereever you want, but the layout is out of the view's hands.&lt;br /&gt;&lt;br /&gt;I hope this is clear. It made a big difference to how I construct views!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3234262719401990699?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3234262719401990699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3234262719401990699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3234262719401990699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3234262719401990699'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/absolving-your-views-of-responsibility.html' title='Absolving your views of responsibility'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-4973671136696074735</id><published>2008-06-11T12:17:00.001+02:00</published><updated>2008-06-17T21:19:10.775+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ultrasphinx'/><title type='text'>Ultrasphinx: ' != "</title><content type='html'>Just ran into a wee ultrasphinx problem.&lt;br /&gt;&lt;br /&gt;I had been doing this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@query = &amp;quot;actor:'#{@person.name}' OR director:'#{@person.name}'&amp;quot;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but it turns out that did nothing! You need to surround query segments in double quotes for it to actually parse them as a single unit:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@query = &amp;quot;actor:\&amp;quot;#{@person.name}\&amp;quot; OR director:\&amp;quot;#{@person.name}\&amp;quot;&amp;quot;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-4973671136696074735?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/4973671136696074735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=4973671136696074735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4973671136696074735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/4973671136696074735'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/ultrasphinx.html' title='Ultrasphinx: &apos; != &quot;'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-3084003086142173620</id><published>2008-06-10T13:52:00.001+02:00</published><updated>2008-06-10T13:58:54.606+02:00</updated><title type='text'>Legitimate job posting?</title><content type='html'>I recently responded to a job posting I saw on jobs.rubynow. The company seemed to like me:&lt;br /&gt;&lt;br /&gt;"Thank you for your interest in ***.  After our first round of resume reviews, we are interested in moving you forward to our next round of evaluations.  This is a significant accomplishment considering the competitive nature of this position, and the small number of candidates for a position that go to on – so congratulations! "&lt;br /&gt;&lt;br /&gt;Wow! Great! Not exactly sure of the English at the end of the sentence there, but cool.&lt;br /&gt;&lt;br /&gt;They then proceeded to ask me a list of questions... all of which I had already answered on the resume they loved so much! But I humored them and answered them again. &lt;br /&gt;A few days later I got this back:&lt;br /&gt;&lt;br /&gt;"A mini-test is a round between resume reviews and interviews, that helps the company get a sense of your real interest in the job, as well as your skills and abilities.  Receiving a mini-test is a pretty significant accomplishment considering the competitive nature of this position, and the small number of  candidates for a position that will receive one – so congratulations! "&lt;br /&gt;&lt;br /&gt;Hmmm surprisingly similar to the first email.&lt;br /&gt;&lt;br /&gt;They wanted me to write a test. Not really what I like to do, but perhaps I'd be interested. But here is the test:&lt;br /&gt;&lt;br /&gt;3.       Code as much of the system as you can within a time-box, which is a maximum of &lt;span style="font-weight:bold;"&gt;10 hours&lt;/span&gt; in this case. &lt;br /&gt;&lt;br /&gt;Uh, they want me to spend 10 HOURS???? on their test!?!&lt;br /&gt;&lt;br /&gt;The real kicker for me was that they sent a spec for the test. It was to write them a new system for their HR department to track resumes! They didn't want a test, they wanted a free application!&lt;br /&gt;&lt;br /&gt;They've made it sound like competition is fierce, so you'd better really do a good job. Now, most developers are proud of what they write and it is a remote test, so why not spend 20 hours or more and create an awesome system! &lt;br /&gt;&lt;br /&gt;Or am I just being paranoid?&lt;br /&gt;&lt;br /&gt;Oh, the also never answered any of my emails. I only got the bulk emails going out to candidates.&lt;br /&gt;&lt;br /&gt;BTW, the company was Rich Applications Consulting,&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-3084003086142173620?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/3084003086142173620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=3084003086142173620' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3084003086142173620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/3084003086142173620'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/legitimate-job-posting.html' title='Legitimate job posting?'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-1441337568554125529</id><published>2008-06-10T09:27:00.000+02:00</published><updated>2008-06-29T15:42:10.241+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ultrasphinx'/><title type='text'>Ultrasphinx cheatsheet: indexing habtm relationships</title><content type='html'>In the previous post I quickly summarized how I am doing the indexing of fields of a model. Quite simple I know.&lt;br /&gt;&lt;br /&gt;I struggled a little bit with getting the other models I wanted indexed to come through.&lt;br /&gt;&lt;br /&gt;Before, as I mentioned, I was using Ferret. Now, despite all of its memory-hog bugginess it is simple to understand because you can modify stuff at the post-sql stage. So before, for instance, I had a method on the film model that did this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def participants_name&lt;br /&gt;    participants.collect{&amp;#124;a&amp;#124; a.name}.join(' ')&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That gave me a big long string and I could pass that to acts_as_ferret and it would use that to find all the films with Johnny Depp in them.&lt;br /&gt;&lt;br /&gt;The problem came with Sphinx not doing any post-sql processing. I wanted the same results, but how?&lt;br /&gt;The model looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Film &amp;lt; ActiveRecord::Base&lt;br /&gt;  has_and_belongs_to_many :participants&lt;br /&gt;...&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;At first I thought I could index participants and then step through all of their films, but that seemed too much work.&lt;br /&gt;&lt;br /&gt;So... here comes the cheatsheet part!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How to index HABTM relationships&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, maybe this is in the documentation but I had a hard time piecing it together.&lt;br /&gt;&lt;br /&gt;I do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;is_index :concatenate =&amp;gt; [&lt;br /&gt;    {:class_name =&amp;gt; &amp;quot;Participant&amp;quot;, &lt;br /&gt;     :field =&amp;gt; &amp;quot;name&amp;quot;, &lt;br /&gt;     :table_alias =&amp;gt; &amp;quot;p1&amp;quot;,&lt;br /&gt;     :as =&amp;gt; &amp;quot;actor&amp;quot;, &lt;br /&gt;     :association_sql =&amp;gt; &amp;quot;LEFT OUTER JOIN films_participants ON (films.`id` = films_participants.`film_id`) LEFT OUTER JOIN participants AS p1 ON (p1.`id` = films_participants.`participant_id`)&amp;quot;}&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;So, where as the :fields array of is_indexed is used for the fields of a model, :concatenate is where you set up the habtm relationships.&lt;br /&gt;To break it down&lt;br /&gt;1 - :class_name =&gt; the name of the class that this model relates to. We need to set this because you can reference by a different name as we'll see in a moment&lt;br /&gt;&lt;br /&gt;2 - :field =&gt; same as the fields table on this model, what field do we want to index on. Not it is called 'field' and not 'fields'! You can only do one.&lt;br /&gt;&lt;br /&gt;3 - :table_alias =&gt; i.e. GODSEND! I have 2 Participant habtm in my film model - one for actors and one for directors. The directors :concatentate definition is almost exactly the same as the actors one. If we didn't have :table_alias Sphinx wouldn't be able to tell them apart. Remember, Sphinx uses all this cleverness to generate one (very clever!) bit of sql.&lt;br /&gt;&lt;br /&gt;4 - :as =&gt; what you want to call this in your search. I can then write a query that says "actor:'Johnny Depp'" and it will search only on that field.&lt;br /&gt;&lt;br /&gt;5 - :association_sql =&gt; yes, Virginia, I am sorry but you have to write your own sql. It will ALWAYS look like this, so just copy and past mine and replace the table and column names.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's it.&lt;br /&gt;&lt;br /&gt;You can now do a query like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@films = Ultrasphinx::Search.new(:query =&amp;gt; &amp;quot;Johnny Depp&amp;quot;, :class_names =&amp;gt; ['Film']).run&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And it will search for any film titles with Johnny Depp in them AND any actors in the film. Sweet!&lt;br /&gt;&lt;br /&gt;Now, didn't I say something about directors?&lt;br /&gt;&lt;br /&gt;I have another habtm relationship:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt; has_and_belongs_to_many :directors, :class_name =&amp;gt; &amp;quot;Participant&amp;quot;, &lt;br /&gt;                            :join_table =&amp;gt; &amp;quot;directors_films&amp;quot;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Same other model (Participant). So now my :concatenate will look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;:concatenate =&amp;gt; [              &lt;br /&gt;                {:class_name =&amp;gt; &amp;quot;Participant&amp;quot;, :field =&amp;gt; &amp;quot;name&amp;quot;, :table_alias =&amp;gt; &amp;quot;p1&amp;quot;,&lt;br /&gt;                :as =&amp;gt; &amp;quot;actor&amp;quot;, :association_sql =&amp;gt; &amp;quot;LEFT OUTER JOIN films_participants ON (films.`id` = films_participants.`film_id`) LEFT OUTER JOIN participants AS p1 ON (p1.`id` = films_participants.`participant_id`)&amp;quot;},&lt;br /&gt;                {:class_name =&amp;gt; &amp;quot;Participant&amp;quot;, :field =&amp;gt; &amp;quot;name&amp;quot;, :table_alias =&amp;gt; &amp;quot;p2&amp;quot;,&lt;br /&gt;                  :as =&amp;gt; &amp;quot;director&amp;quot;, :association_sql =&amp;gt; &amp;quot;LEFT OUTER JOIN directors_films ON (films.`id` = directors_films.`film_id`) LEFT OUTER JOIN participants AS p2 ON (p2.`id` = directors_films.`participant_id`)&amp;quot;}]&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Two references to Participant, but :table_alias saves the day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-1441337568554125529?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/1441337568554125529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=1441337568554125529' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1441337568554125529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/1441337568554125529'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/ultrasphinx-cheatsheet-indexing-habtm.html' title='Ultrasphinx cheatsheet: indexing habtm relationships'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-2000851350348321607</id><published>2008-06-09T16:28:00.000+02:00</published><updated>2008-06-19T13:24:09.710+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ultrasphinx'/><title type='text'>Ultrasphinx cheatsheet: indexing fields you need!</title><content type='html'>The Sphinx/Ultrasphinx combination is great for searching. Very fast and much less load on your database than other options. It also takes a lot less memory and is more reliable.&lt;br /&gt;&lt;br /&gt;But, the documentation is maddening. Here is what I have learned about implementing it.&lt;br /&gt;&lt;br /&gt;To index a field on a model:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;is_indexed :fields =&amp;gt; [{:field =&amp;gt; :field_name, :sortable =&amp;gt; true}]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The sortable lets you sort on it later in searches. The thing to remember is that sphinx knows nothing except what you explicitly tell it. So it won't know about fields you don't mention, or what you might want to do with those fields. Don't include the :sortable flag and you can't sort on it.&lt;br /&gt;&lt;br /&gt;To that end, we have a field called 'available' that we set/unset if an item in the catalogue shouldn't be displayed online. Now, we never really want to search on that, but, we do want to include it in searches as a filter. So, the first line of our model is really this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;is_indexed  :fields =&amp;gt; [{:field =&amp;gt; :title, :facet =&amp;gt; true, :sortable =&amp;gt; true}, :available]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That means we can do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@films = Ultrasphinx::Search.new(:query =&amp;gt; &amp;quot;title:Foo&amp;quot;, :class_names =&amp;gt; ['Film'], :filters =&amp;gt; {&amp;quot;available&amp;quot; =&amp;gt; 1}).run&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And we'll just get a list of available films named Red (or with Red in the title).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-2000851350348321607?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/2000851350348321607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=2000851350348321607' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2000851350348321607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/2000851350348321607'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/ultrasphinx-cheatsheet-indexing-fields.html' title='Ultrasphinx cheatsheet: indexing fields you need!'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3255107130863381139.post-7676397041889278999</id><published>2008-06-08T08:40:00.000+02:00</published><updated>2008-06-08T09:58:05.869+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='utf8'/><category scheme='http://www.blogger.com/atom/ns#' term='ultrasphinx'/><category scheme='http://www.blogger.com/atom/ns#' term='encoding'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Ultrasphinx &amp; UTF-8 data</title><content type='html'>On &lt;a href="http://www.filmamora.com"&gt;filmamora.com&lt;/a&gt; we obviously have a lot of data that is not your standard ascii - Spanish film titles and Actor's name especially.&lt;br /&gt;&lt;br /&gt;After switching from &lt;a href="http://ferret.davebalmain.com/"&gt;Ferret&lt;/a&gt; to &lt;a href="http://www.sphinxsearch.com/"&gt;Sphinx&lt;/a&gt; as a search engine (more about this in another post) everything was going great using the &lt;a href="http://blog.evanweaver.com/files/doc/fauna/ultrasphinx/files/README.html"&gt;ultrasphinx&lt;/a&gt; plugin. That is until I tested searching on a name like 'Belén'. No films were found with an actress with that name - though I knew there were loads of actresses with that name and therefore films.&lt;br /&gt;&lt;br /&gt;The problem was the data settings in the database. Even though I was displaying the names correctly this was due to a transliteration between the characters in the database and the webpage. The data was not being stored correctly.&lt;br /&gt;&lt;br /&gt;You MUST create tables as default charset utf8 to get the correct results:&lt;br /&gt;&lt;br /&gt;Step 1) Create the table in a migration&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create_table(:films, :options =&gt; 'DEFAULT CHARSET=utf8') do |t|&lt;br /&gt;      t.string :title, :null =&gt; false&lt;br /&gt;      ....&lt;br /&gt;    end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Step 2) Tell rails that the database is in utf-8 by putting this in your database.yml:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;development:&lt;br /&gt;  adapter: mysql&lt;br /&gt;  database: filmamora_development&lt;br /&gt;  encoding: utf8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Step 3) Make sure the data going IN is in utf8. Filmamora gets a lot of data from scraping our wholesales site (using scrapi), so I do this:&lt;br /&gt;&lt;br /&gt;    film_info_es = dvdgo_movie.scrape(URI.parse("#{server}/#{page}"), &lt;br /&gt;                      :parser_options =&gt; {"char-encoding" =&gt; "latin0", &lt;br /&gt;                        "output-encoding" =&gt; "utf8", "quote-marks" =&gt; "true" },&lt;br /&gt;                      :user_agent =&gt; "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Step 4) search!&lt;br /&gt;      @films = Ultrasphinx::Search.new(:query =&gt; @query, :class_names =&gt; ['Film'], &lt;br /&gt;                      :page =&gt; params[:page]||1, :per_page =&gt; 12, &lt;br /&gt;                      :filters =&gt; {"available" =&gt; 1}).run&lt;br /&gt;&lt;br /&gt;Now, if you were (like us) unlucky enough to have NOT done this from the start and can't re-run your migrations (we have a catalogue of 35,000 items!), you can do this to your tables:&lt;br /&gt;&lt;br /&gt;ALTER TABLE mytablename DEFAULT CHARACTER SET utf8&lt;br /&gt;&lt;br /&gt;We then deleted all our character data (film titles, actor's name, synopsis) and reimported. We kept our id's (which we needed to make sure our existing orders and wishlists, etc didn't go wrong) but got the new data.&lt;br /&gt;&lt;br /&gt;In theory you don't need to set the charset on each table. In MySQL you can create a database with a default charset:&lt;br /&gt;&lt;br /&gt;CREATE TABLE tablename DEFAULT CHARACTER SET utf8;&lt;br /&gt;&lt;br /&gt;And then all your tables should use it too.&lt;br /&gt;&lt;br /&gt;But, I don't think that rake db:create does this... (maybe it does now that I have set the character set in the database.yml... hmmm). I also am not sure if the rake db tasks to create tables explicitly set the charset or not. Anyone?&lt;br /&gt;&lt;br /&gt;I'm going to write a few posts on sphinx/ultrasphinx because it is so awesome and I had some issues finding clear info on how to use it, so I might as well write it up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3255107130863381139-7676397041889278999?l=rorramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rorramblings.blogspot.com/feeds/7676397041889278999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3255107130863381139&amp;postID=7676397041889278999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7676397041889278999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3255107130863381139/posts/default/7676397041889278999'/><link rel='alternate' type='text/html' href='http://rorramblings.blogspot.com/2008/06/ultrasphinx-utf-8-data.html' title='Ultrasphinx &amp; UTF-8 data'/><author><name>Phil Smy</name><uri>http://www.blogger.com/profile/02013604704411178928</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://bp1.blogger.com/_iy2w4vyQwV0/R-lOiNBCHZI/AAAAAAAAADM/eI4Fpy9-mHE/S220/face2.jpg'/></author><thr:total>0</thr:total></entry></feed>
