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

<channel>
	<title>John&#039;s Tidbits &#187; rails</title>
	<atom:link href="http://inodes.org/tag/rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://inodes.org</link>
	<description>Moo - Development, Trouble-shooting and Random thoughts...</description>
	<lastBuildDate>Thu, 19 Apr 2012 10:15:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.1</generator>
		<item>
		<title>Adding multiple database support to Cucumber</title>
		<link>http://inodes.org/2009/10/08/adding-multiple-database-support-to-cucumber/</link>
		<comments>http://inodes.org/2009/10/08/adding-multiple-database-support-to-cucumber/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 06:46:16 +0000</pubDate>
		<dc:creator>johnf</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[transactions]]></category>
		<category><![CDATA[vquence]]></category>

		<guid isPermaLink="false">http://inodes.org/?p=210</guid>
		<description><![CDATA[The Vqmetrics application needs to connect to two different databases. The first holds the videos, authors and their relevant statistics, while the second database holds the users, monitors and trackers. We do this by specifying two databases in config/database.yml. development: database: vqmetrics_devel &#60; &#60;: *login_dev_local &#160; vqdata_development: &#38;VQDATA_TEST database: vqdata_devel &#60;&#60;: *login_dev_local So by default [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://vquence.com.au">Vqmetrics</a> application needs to connect to two different databases. The first holds the videos, authors and their relevant statistics, while the second database holds the users, monitors and trackers.</p>
<p>We do this by specifying two databases in <strong>config/database.yml</strong>.</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">development:
  database: vqmetrics_devel
  &lt; &lt;: *login_dev_local
&nbsp;
vqdata_development: &amp;VQDATA_TEST
  database: vqdata_devel
  &lt;&lt;: *login_dev_local</pre></div></div>

<p>So by default the <strong>vqmetrics_devel</strong> database will be used. When we need to specify a  model where we need to connect to the <strong>vqdata_devel</strong> database we use</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Video <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  establish_connection <span style="color:#996600;">&quot;vqdata_#{RAILS_ENV}&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>and for migrations that need to connect to this database we do the following.</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> InitialSetup <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Migration</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">connection</span>
    Video.<span style="color:#9900CC;">connection</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>This setup works really well. However recently I moved this application to using <a href="http://cukes.info">Cucumber</a> for testing. Tests worked fine the first time they are run but not the second time.</p>
<p>I discovered that the transaction on the second database where not being rolled back as they should be. Cucumber only sets up the first database for roll back by using </p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>.<span style="color:#9900CC;">connection</span></pre></div></div>

<p>where it should be rolling them all back by looping through</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>.<span style="color:#9900CC;">connection_handler</span>.<span style="color:#9900CC;">connection_pools</span>.<span style="color:#9900CC;">values</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>pool<span style="color:#006600; font-weight:bold;">|</span> pool.<span style="color:#9900CC;">connection</span><span style="color:#006600; font-weight:bold;">&#125;</span></pre></div></div>

<p>I've filed a bug at <a href="https://rspec.lighthouseapp.com/projects/16211-cucumber/tickets/480-cucumber-only-turns-on-transactions-for-one-database">lighthouseapp</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://inodes.org/2009/10/08/adding-multiple-database-support-to-cucumber/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Squid and Rails caching</title>
		<link>http://inodes.org/2008/01/15/squid-and-rails-caching/</link>
		<comments>http://inodes.org/2008/01/15/squid-and-rails-caching/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 13:04:35 +0000</pubDate>
		<dc:creator>johnf</dc:creator>
				<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[squid]]></category>

		<guid isPermaLink="false">http://inodes.org/blog/2008/01/15/squid-and-rails-caching/</guid>
		<description><![CDATA[At Vquence our Rails setup looks something like this. ------------ --------- ------------ &#124; Internet &#124;---->&#124; Squid &#124;---->&#124; Mongrels &#124; ------------ --------- ------------ (Who needs Inkscape when you have ASCII art) This infrastructure is hosted in the US and up until recently squid hadn&#8217;t been doing much of anything except really sitting there. Now a few [...]]]></description>
			<content:encoded><![CDATA[<p>At Vquence our Rails setup looks something like this.</p>
<pre>
------------     ---------     ------------
| Internet |---->| Squid |---->| Mongrels |
------------     ---------     ------------
</pre>
<p>(Who needs Inkscape when you have ASCII art)</p>
<p>This infrastructure is hosted in the US and up until recently squid hadn&#8217;t been doing much of anything except really sitting there.</p>
<p>Now a few months ago when we signed a contract with an Australian customer we decided we needed to place a squid cache in Australia which would actually cache content. For two reasons, firstly the US is a long way away and the 300ms latency is really noticeable and secondly because some of our pages involving graphs have long statistical calculations which can take minutes to render. (OK its really because no one has had a chance to optimise them yet but lets pretend that&#8217;s not the case). So we changed the above setup for the Australian customers to look like the following.</p>
<pre>
------------     ------------     ------------     ------------
| Internet |---->| Squid AU |---->| Squid US |---->| Mongrels |
------------     ------------     ------------     ------------
</pre>
<p>We hand out urls like http://www.client.b2b.vquence.com/widget to Australian customers and the rails backend is smart enough to make sure all the URLs look similar (I&#8217;ll blog about how I did that another time).</p>
<p>Without much time to look into thing properly I did some really nasty things on the AU squid cache to make sure it cached the pages.</p>
<pre name="code">
refresh_pattern /client/graph  1440    0%    1440    ignore-no-cache ignore-reload
refresh_pattern /client/static 1440    0%    1440    ignore-no-cache ignore-reload
refresh_pattern /client/video  1440    0%    1440    ignore-no-cache ignore-reload
</pre>
<p>This is evil, breaks a whole heap of RFCs but it did the trick and got us out of a bind quickly.</p>
<p>A few weeks ago I moved the production site to Rails 2.0, I noticed around this time that the caching had stopped working. The client was no longer using our services as their campaign had finished so it wasn&#8217;t an urgent concern.</p>
<p>It seems that Rails 2.0 goes one step further to ensure that caches don&#8217;t cache content and instead of just sending</p>
<pre name="code">
Cache-Control: no-cache
</pre>
<p>it now sends</p>
<pre name="code">
Cache-Control: private, max-age=0, must-revalidate
</pre>
<p>I tried adding <b>ignore-private</b>, since if you&#8217;re breaking some aspects of the RFC you may as well break a couple more, but squid still refused to cache the content. After struggling with this for a bit I decided that the universe was trying to tell me I should actually do things properly.</p>
<p>So with squid set back to its defaults I went exploring how to accomplish this. Google wasn&#8217;t all that helpful at first since most Rails caching articles talk about caching to static files as most sites don&#8217;t implement reverse proxying for caching. It turns out however its fairly simple. In the appropriate actions in your controllers simply do the following.</p>
<pre name="code" class="ruby">
class VideoController < ApplicationController

    def vquence
        # Lots of code here

        expires_in 8.hours, :private => false
        render :template => "videos/vquence"
    end

end
</pre>
<p>This will send the following header and cache the page for 8 hours.</p>
<pre name="code">
Cache-Control: max-age=28800
</pre>
<p>Now everything is much faster!!</p>
]]></content:encoded>
			<wfw:commentRss>http://inodes.org/2008/01/15/squid-and-rails-caching/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Rails, ActiveRecord, MySQL, GUIDs and the rename_column bug</title>
		<link>http://inodes.org/2008/01/11/rails-activerecord-mysql-guids-and-the-rename_column-bug/</link>
		<comments>http://inodes.org/2008/01/11/rails-activerecord-mysql-guids-and-the-rename_column-bug/#comments</comments>
		<pubDate>Fri, 11 Jan 2008 10:25:01 +0000</pubDate>
		<dc:creator>johnf</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[guid]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[vquence]]></category>

		<guid isPermaLink="false">http://inodes.org/blog/2008/01/11/rails-activerecord-mysql-guids-and-the-rename_column-bug/</guid>
		<description><![CDATA[Since I wasted over 4 hours of my life today working my way through this problem I feel the need to share. Since it seems to be the in thing in the Web 2.0 space, just to be cool, we use GUIDs to identify different objects in our URLs at Vquence. For example my randomly [...]]]></description>
			<content:encoded><![CDATA[<p>Since I wasted over 4 hours of my life today working my way through this problem I feel the need to share.</p>
<p>Since it seems to be the in thing in the Web 2.0 space, just to be cool, we use <a href="http://en.wikipedia.org/wiki/Globally_Unique_Identifier">GUIDs</a> to identify different objects in our URLs at <a href="http://vquence.com">Vquence</a>. For example my randomly created vquence on on <a href="http://www.vqslices.com/vq/cDuIhGWb8r3lDxaby-aaea">Rails</a> has a GUID of</p>
<pre>cDuIhGWb8r3lDxaby-aaea</pre>
<p>Andy Singleton has written a rails plugin called funnily enough <a href="http://tools.assembla.com/breakout/wiki/FreeSoftware">guid</a>. This allows you to do the following in your model.</p>
<pre class="ruby">class Vquence &lt; ActiveRecord::Base
  usesguid :column =&gt; 'guid'
end</pre>
<p>Once you do this you will automatically get GUID looking identifiers in the db and your application. The <strong>guid</strong> column in the DB gets mapped to <strong>Vquence.id</strong> so you can do things like</p>
<pre class="ruby">Vquence.find('cDuIhGWb8r3lDxaby-aaea');</pre>
<p>We used to use <a href="http://www.sphinxsearch.com/">Sphinx</a> as our search index, we now use <a href="http://lucene.apache.org/">Lucene</a>. Sphinx requires that you have an integer id for each document in your index. This is to make your SQL queries much faster. The dumb way to create your index is to use queries like the following.</p>
<pre class="sql">SELECT * FROM videos LIMIT 0,10000
SELECT * FROM videos LIMIT 10000,10000
...
SELECT * FROM videos LIMIT 990000,10000</pre>
<p>I know this as its what we originally used with Lucene. This works fine until you reach about 1,000,000 rows. The problem is that since there is no implicit ordering or range in the above query it means that for the final query MySQL needs to workout what the first 1,000,000 rows are and then return you the last 10,000.</p>
<p>A much better way to do it is the following</p>
<pre class="sql">SELECT * FROM videos WHERE integer_id &gt;= 1 and integer_id &lt; = 10000
SELECT * FROM videos WHERE integer_id &gt;= 10001 and integer_id &lt; = 20000
...
SELECT * FROM videos WHERE integer_id &gt;= 990000 and integer_id &lt; = 1000000</pre>
<p>This is fast as long as <strong>integer_id</strong> is indexed.</p>
<p>So to accommodate this in Rails we began using migrations like the following.</p>
<pre class="ruby">class Videos &lt; ActiveRecord::Migration
  def self.up
    create_table :videos do |t|
      t.column :uuid, :string, :limit =&gt;22, :null =&gt; false
      ...

      t.timestamps
    end
    add_index :videos, :uuid, :unique =&gt; true
    rename_column :videos, :id, :integer_id
  end

  def self.down
    drop_table :videos
  end
end</pre>
<p>This was all done months ago and the repercussions didn&#8217;t rear their ugly head until today. Previously everything in the videos table had been created by our external crawler and Rails never needed to insert into the table. Today I wrote some code that inserted into the videos table and everything broke horribly.</p>
<p>The problem is that ActiveRecord can still see the <strong>integer_id</strong> field and tries to insert a 0 value into it. It isn&#8217;t clever enough to realise that it is an auto increment field and to leave it alone. After some help from <em>bitsweat</em> on #RoR I implemented a dirty hack to hide the <strong>integer_id</strong> column from ActiveRecord. Thanks to Ruby overriding the ActiveRecord internals is really easy and I added the following to our guid plugin.</p>
<pre class="ruby">  # HACK (JF) - This is too evil to even blog about
  # When we use guid as a primary key we usually rename the original 'id'
  # field to 'integer_id'. We need to hide this from rails so it doesn't
  # mess with it. WARNING: This means once you use usesguid anywhere you can
  # never access a column in any table anywhere called 'integer_id'

class ActiveRecord::Base
  private
    alias <img src='http://inodes.org/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> riginal_attributes_with_quotes :attributes_with_quotes

    def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true)
      quoted = original_attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true)
      quoted.delete('integer_id')
      quoted
    end
end</pre>
<p>So this worked like a charm and after 4 hours I thought my pain was over, but then I tried to add second row to my test database. This resulted in the following.</p>
<pre> Mysql::Error: Duplicate entry '0' for key 1: INSERT INTO `videos` (`updated_at`, `sort_order`, `guid`, `description`,
 `user_id`, `created_at`) VALUES('2008-01-11 16:45:05', NULL, 'bcOMPqWaGr3k5CabxfFyeK', '', 5, '2008-01-11 16:44:28');</pre>
<p>I ran the same SQL with MySQL client and got the same error. I then looked at the table and saw the following</p>
<pre>mysql&gt; show columns from moo;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| integer_id | int(11)     | NO   | PRI | 0       |       |
| guid       | varchar(22) | NO   | UNI |         |       |
+------------+-------------+------+-----+---------+-------+</pre>
<p>What I expected to see was</p>
<pre>mysql&gt; show columns from moo;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| integer_id | int(11)     | NO   | PRI | NULL    | auto_increment |
| guid       | varchar(22) | NO   | UNI |         |                |
+------------+-------------+------+-----+---------+----------------+</pre>
<p>The difference is that when the column was renamed it seems to have lost its auto increment and NOT NULL properties. Some investigation showed that the SQL being used to rename the column was</p>
<pre class="sql">ALTER TABLE `videos` CHANGE `id` `integer_id` int(11)</pre>
<p>when it should be</p>
<pre class="sql">ALTER TABLE `videos` CHANGE `id` `integer_id` int(11) NOT NULL AUTO_INCREMENT</pre>
<p>It seems that this is already filled as a <a href="http://dev.rubyonrails.org/ticket/6999">bug</a> on the rails site, including a patch.</p>
<p>Funnily enough that bug is owned by <strong>bitsweat</strong>. It seems he&#8217;s managed to help me out twice in one day <img src='http://inodes.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  It doesn&#8217;t seem that it made it into Rails 2.0 though so until then be careful about renaming columns using migrations.</p>
]]></content:encoded>
			<wfw:commentRss>http://inodes.org/2008/01/11/rails-activerecord-mysql-guids-and-the-rename_column-bug/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mongrel, rails and the theory of relativity</title>
		<link>http://inodes.org/2007/04/04/mongrel-rails-and-the-theory-of-relativity/</link>
		<comments>http://inodes.org/2007/04/04/mongrel-rails-and-the-theory-of-relativity/#comments</comments>
		<pubDate>Wed, 04 Apr 2007 05:15:06 +0000</pubDate>
		<dc:creator>johnf</dc:creator>
				<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mogrel]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[vquence]]></category>

		<guid isPermaLink="false">http://inodes.org/blog/2007/04/04/mongrel-rails-and-the-theory-of-relativity/</guid>
		<description><![CDATA[Summary (E = mc&#178;) When using mongrel for rails and you want to deploy an app under /other_url then use ActionController::AbstractRequest.relative_url_root = "/other_url" in config/environments/production.rb instead of ENV['RAILS_RELATIVE_URL_ROOT'] = "/other_url" Proof (From first principals) At Vquence we have a pretty standard rails setup Apache with mod_proxy pen mongrel Silvia recently wrote an application to allow [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Summary (E = mc&sup2;)</strong></p>
<p>When using mongrel for rails and you want to deploy an app under /other_url then use</p>
<pre>
    ActionController::AbstractRequest.relative_url_root = "/other_url"
</pre>
<p>in config/environments/production.rb instead of</p>
<pre>
    ENV['RAILS_RELATIVE_URL_ROOT'] = "/other_url"
</pre>
<p><strong>Proof (From first principals)</strong></p>
<p>At <a href="http://www.vquence.com">Vquence</a> we have a pretty standard rails setup</p>
<ul>
<li>Apache with mod_proxy</li>
<li>pen</li>
<li>mongrel</li>
</ul>
<p><a href="http://blog.gingertech.net">Silvia</a> recently wrote an application to allow us to edit the news articles posted to our corporate website. I wanted to do something I thought would be pretty simple, have the application appear at /news on our admin web server.</p>
<p>Step one was the obvious change to mod_proxy</p>
<pre>
    ProxyPass /news http://localhost:8000
    ProxyPassReverse /news http://localhost:8000
</pre>
<p>Of course the problem is that the rails app still thinks it is living on <em>/</em> so it returns URLs like <em>/stylesheets/moo.css</em> instead of <em>/news/stylesheets/moo.css</em>.</p>
<p>A bit of googling found a few email threads with a common solution. In your environment.rb set</p>
<pre>
    ENV['RAILS_RELATIVE_URL_ROOT'] = "/other_url"
</pre>
<p>This is where things fell apart fairly quickly. I could not get this to work no matter what I tried. After a few hours of following a HTTP request through the whole Mongrel and rails stack I discovered the following.</p>
<p>Setting <em>RAILS_RELATIVE_ROOT</em> will work fine if you are running rails using CGI. For the simple reason, which should have been more obvious to me sooner, that CGIs use environment variables to access their parameters. This can be seen in the<br />
ruby CGI class</p>
<p>/usr/lib/ruby/1.8/cgi.rb:</p>
<pre name="code" class="ruby">

class CGI

def env_table
    ENV
end
</pre>
<p>However mongrel overloads <em>env_table</em> and does the following instead</p>
<p>/usr/lib/ruby/1.8/mongrel/cgi.rb:</p>
<pre name="code" class="ruby">

class CGIWrapper < ::CGI

    # Used to wrap the normal env_table variable used inside CGI.
    def env_table
        @request.params
    end
</pre>
<p>This makes sense since the rails code is now running inside the web server so environment variables aren't necessary. Upon investigation I found that the URL morphing magic is performed with rails as follows.</p>
<p>/usr/share/rails/actionpack/lib/action_controller/request.rb:
</pre>
<pre name="code" class="ruby">

  class AbstractRequest
    cattr_accessor :relative_url_root

    # Returns the path minus the web server relative installation directory.
    # This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
    # It can be automatically extracted for Apache setups. If the server is not
    # Apache, this method returns an empty string.
    def relative_url_root
      @@relative_url_root ||= case
        when @env["RAILS_RELATIVE_URL_ROOT"]
          @env["RAILS_RELATIVE_URL_ROOT"]
        when server_software == 'apache'
          @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
        else
          ''
      end
    end
</pre>
<p>What this all means is that you can solve the whole problem by placing the following in your <em>config/environments/production.rb</em></p>
<pre name="code" class="ruby">
    ActionController::AbstractRequest.relative_url_root = "/other_url"
</pre>
<p>Now if only Einstein had put his theories to good use and invented a time machine then maybe I could get the last 4 hours of my life back <img src='http://inodes.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Update:</strong> Make sure <em>/other_url</em> isn&#8217;t the same name as one of your controllers or <strong>bad</strong> things happen.</p>
]]></content:encoded>
			<wfw:commentRss>http://inodes.org/2007/04/04/mongrel-rails-and-the-theory-of-relativity/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
