<?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>MJCBlog.Net</title>
	<atom:link href="http://www.mjcblog.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mjcblog.net</link>
	<description></description>
	<lastBuildDate>Mon, 09 Jan 2012 18:20:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Easy Integration of Minitest::Spec and VCR</title>
		<link>http://www.mjcblog.net/2011/09/easy-integration-of-minitestspec-and-vcr/</link>
		<comments>http://www.mjcblog.net/2011/09/easy-integration-of-minitestspec-and-vcr/#comments</comments>
		<pubDate>Mon, 12 Sep 2011 19:18:11 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[minitest]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[vcr]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=409</guid>
		<description><![CDATA[I&#8217;m a big fan of MiniTest. I use it for basically all of my testing in Ruby. I&#8217;ve also started to use VCR to help with stubbing and recording HTTP requests during tests. In a nutshell, VCR lets hit the actual resource on the first run. VCR then records the results and replays them back [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big fan of <a href="http://https://github.com/seattlerb/minitest" title="MiniTest">MiniTest</a>. I use it for basically all of my testing in Ruby. I&#8217;ve also started to use <a href="https://github.com/myronmarston/vcr" title="VCR">VCR</a> to help with stubbing and recording HTTP requests during tests. In a nutshell, VCR lets hit the actual resource on the first run. VCR then records the results and replays them back on subsequent test runs. It really helps to speed up tests and isolate externals.</p>
<p>Recently, I had to integrate VCR with MiniTest::Spec. MiniTest by default runs tests in random order. Additionally, there is no <code>after(:all)</code> hook available in MiniTest. When integrating MiniTest with VCR, tests which would have otherwise been unaffected by order may now produce false failures due to VCR.</p>
<p>This is when I came up with a rather simple solution to have each test run in isolation and have their own specific cassette. At my top level <code>describe</code> block for each test file, I have a <code>before</code> block that sets up a VCR cassette for each expectation. Here&#8217;s the code for this solution (and a <a href="https://gist.github.com/1212114" title="Github Gist">gist</a>):</p>
<p><code>
<pre>
describe "Something" do
  before do
    # __name__ defined in MiniTest::Unit::TestCase
    VCR.insert_cassette __name__
  end

  after do
    VCR.eject_cassette
  end
end
</pre>
<p></code></p>
<p>Now every single <code>it</code> or <code>specify</code> block that makes one or more HTTP requests will generate and use it&#8217;s own cassette. Granted, this solution is somewhat verbose in the amount of cassettes that are generated. I feel however, this is a reasonable trade off for its sheer simplicity!</p>
<p><strong>Update:</strong> I added this solution and some more general information about MiniTest to VCR&#8217;s <a href="https://github.com/myronmarston/vcr/wiki/Usage-with-MiniTest" title="Usage with MiniTest">wiki</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/09/easy-integration-of-minitestspec-and-vcr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>nginx Custom Maintenance Page without Redirects</title>
		<link>http://www.mjcblog.net/2011/08/nginx-custom-maintenance-page-without-redirects/</link>
		<comments>http://www.mjcblog.net/2011/08/nginx-custom-maintenance-page-without-redirects/#comments</comments>
		<pubDate>Mon, 08 Aug 2011 15:46:25 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[deploying]]></category>
		<category><![CDATA[nginx]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=357</guid>
		<description><![CDATA[For BreakBase, we use nginx as a reverse proxy to our app server. When we deploy updates, the upstream app server is temporarily offline. Rather than have nginx respond with the default &#8220;502 Bad Gateway&#8221; page, we replace it with our own maintenance page. Additionally, we also need to make sure our maintenance page does [...]]]></description>
			<content:encoded><![CDATA[<p>For <a href="http://breakbase.com">BreakBase</a>, we use nginx as a reverse proxy to our app server. When we deploy updates, the upstream app server is temporarily offline. Rather than have nginx respond with the default &#8220;502 Bad Gateway&#8221; page, we replace it with our own maintenance page. Additionally, we also need to make sure our maintenance page does not redirect the user so their requested URI stays the same. That way when the upstream server is back online, a simple refresh will take the user to their originally requested page.</p>
<p>Below is the configuration for our maintenance page:</p>
<pre>
error_page 502 =200 @maintenance;
location @maintenance {
    root /path/to/maintenance;
    try_files $uri $uri/ /index.html =503;
}
</pre>
<p>There are a lot of things going on in this configuration. First off, we are using a named location with an <code>error_page</code> directive to &#8220;catch&#8221; the 502 error. Secondly, the <code>=200</code> in this directive is used to set the response code to 200. This is done so browsers properly render the page as well as any CSS or images that are included.</p>
<p>Finally, we use the <code>try_files</code> directive in order to first try and serve the requested file (for CSS and images). If these files are not found, it will then try and serve an <code>index.html</code> file. If for some reason <code>index.html</code> is not available, we fallback to the default 503 error page which is more appropriate than the 502 page. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/08/nginx-custom-maintenance-page-without-redirects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5 Data Attributes for Pylons Webhelpers</title>
		<link>http://www.mjcblog.net/2011/07/html5-data-attributes-for-pylons-webhelpers/</link>
		<comments>http://www.mjcblog.net/2011/07/html5-data-attributes-for-pylons-webhelpers/#comments</comments>
		<pubDate>Sat, 16 Jul 2011 05:42:04 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[BreakBase]]></category>
		<category><![CDATA[data-attributes]]></category>
		<category><![CDATA[helpers]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[pylons]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=266</guid>
		<description><![CDATA[HTML5 data attributes let developers store bits of meta-data directly within markup. They are an incredibly useful tool and I would highly recommend checking out the first few hits on Google for more details on exactly how they are used. While working on BreakBase, I can across a bit of an issue with creating data [...]]]></description>
			<content:encoded><![CDATA[<p>HTML5 data attributes let developers store bits of meta-data directly within markup. They are an incredibly useful tool and I would highly recommend checking out the first few hits on <a href="http://www.google.com/search?q=html5+data+attributes">Google</a> for more details on exactly how they are used. </p>
<p>While working on <a href="http://breakbase.com">BreakBase</a>, I can across a bit of an issue with creating data attributes using Pylons&#8217; Webhelper tags. Attributes are generally assigned in Webhelper tags using Python kwargs. This is an issue since data attributes require a dash character, which results in invalid Python code. Additionally, we use Mako templates so using an inline dict object is not an option since it will clash with the Mako delimiters. </p>
<p>Thus, I created a really simple helper that we can use in the meanwhile until data attribute support is added to Webhelpers directly. Here the helper method definition (and a <a href="https://gist.github.com/1086040">github gist</a>):</p>
<p><code>
<pre>
def data_attrs(**kwargs):
    attrs = {}
    for suffix in kwargs:
        key = "data-%s" % suffix
        attrs[key] = kwargs[suffix]

    return attrs
</pre>
<p></code></p>
<p>To use this helper, simply do the following:</p>
<p><code>${ h.link_to("link text", "/some/url", **h.data_attrs(some="data", available="here")) }</code></p>
<p>Which will produce the following <em>valid</em> markup:</p>
<p><code>&lt;a href=&quot;/some/url&quot; data-some=&quot;data&quot; data-available=&quot;here&quot;&gt;link text&lt;/a&gt;</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/07/html5-data-attributes-for-pylons-webhelpers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing jQuery.whiny.js</title>
		<link>http://www.mjcblog.net/2011/07/introducing-jquery-whiny-js/</link>
		<comments>http://www.mjcblog.net/2011/07/introducing-jquery-whiny-js/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 04:06:29 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=252</guid>
		<description><![CDATA[We&#8217;ve all done something like this: $('#id').text('new text'); And wondered why the code wasn&#8217;t working only to find out the selector was wrong. jQuery.whiny.js attempts to solve this problem by altering the jQuery library so the jQuery() method will create a console warning if an empty jQuery object returned. In the above example, if &#8216;#id&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve all done something like this:</p>
<p><code>$('#id').text('new text');</code></p>
<p>And wondered why the code wasn&#8217;t working only to find out the selector was wrong. jQuery.whiny.js attempts to solve this problem by altering the jQuery library so the jQuery() method will create a console warning if an empty jQuery object returned. </p>
<p>In the above example, if &#8216;#id&#8217; returned an empty jQuery object you&#8217;d see the following console warning:</p>
<p><code>jQuery was called with a selector of '#id' and returned an empty object</code></p>
<p>Please note, this is only for dev purposes. To get the jQuery.whiny.js, head over to the <a href="https://github.com/mikeycgto/jquery.whiny.js">github project</a>. Additionally, the name of this script was inspired by &#8220;whiny nil&#8221; from Ruby on Rails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/07/introducing-jquery-whiny-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery Selector Injection</title>
		<link>http://www.mjcblog.net/2011/06/jquery-selector-injection/</link>
		<comments>http://www.mjcblog.net/2011/06/jquery-selector-injection/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 17:23:45 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[injection]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[xss]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=225</guid>
		<description><![CDATA[First off, this type of issue is more theoretical than anything. jQuery allows you create HTML elements on the fly via the jQuery() method. Creating new HTML elements using this technique is common in the jQuery world since it results in more readable, jQuery-esque code. Potential client-side code injection issues can arise if malicious input [...]]]></description>
			<content:encoded><![CDATA[<p>First off, this type of issue is more theoretical than anything. </p>
<p>jQuery allows you create HTML elements on the fly via the <a href="http://api.jquery.com/jQuery/#jQuery2">jQuery() method</a>. Creating new HTML elements using this technique is common in the jQuery world since it results in more readable, jQuery-esque code.</p>
<p>Potential client-side code injection issues can arise if malicious input is passed to this method. Consider the following example:</p>
<p><code>$("&lt;img src='/' onerror=alert('xss');&gt;");</code></p>
<p>This will result in client-side code execution (mainly an alert displaying the string &#8216;xss&#8217;). Nevertheless, it is possible to execute arbitrary client-side code via this vector. To see this in action, check my overly contrived demo\proof-of-concept available <a href="http://www.mjcblog.net/files/jquery-selector-poc.html">here</a>.</p>
<p>Now you should be asking yourself, what does this mean for me as a jQuery developer? In reality, not a whole lot. The main point here is that developers should always be mindful of what input is passed to the jQuery() method. Much like how developers need to be mindful of user-input in order to prevent other XSS issues and DB-level injections. </p>
<p>The bottom-line: <em>never trust user-input</em>.</p>
<p><strong>Update:</strong> This issue has now been partly addressed by jQuery 1.6.3. Refer to <a href="http://bugs.jquery.com/ticket/9521" title="Bug #9521">bug #9521</a> for details on the fix. In short, <code>#id</code> are prioritized over <code>&lt;tag&gt;</code> selectors. </p>
<p>The issue in general however, is still possible with selectors that are not <code>#id</code> based. Take a look at my second overly contrived proof-of-concept <a href="http://www.mjcblog.net/files/jquery-selector-poc-w-class.html">here</a> which uses a <code>.class</code> selector instead of an <code>#id</code> one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/06/jquery-selector-injection/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing BreakBase.com</title>
		<link>http://www.mjcblog.net/2011/06/introducing-breakbase-com/</link>
		<comments>http://www.mjcblog.net/2011/06/introducing-breakbase-com/#comments</comments>
		<pubDate>Fri, 03 Jun 2011 03:15:21 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General Banter]]></category>
		<category><![CDATA[BreakBase]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=220</guid>
		<description><![CDATA[A few friends of mine and myself have been hard at work over the past few months on BreakBase. We finally opened the doors to the public on May 26th, 2011. The idea behind BreakBase is simple: play your favorite board games with anyone you&#8217;d like. It&#8217;s totally free to use and you don&#8217;t even [...]]]></description>
			<content:encoded><![CDATA[<p>A few friends of mine and myself have been hard at work over the past few months on <a href="http://breakbase.com">BreakBase</a>. We finally opened the doors to the public on May 26th, 2011.</p>
<p>The idea behind BreakBase is simple: play your favorite board games with anyone you&#8217;d like. It&#8217;s totally free to use and you don&#8217;t even an account to start playing! So, head on over to <a href="http://breakbase.com">BreakBase</a> and start playing. </p>
<p><em>PS: There a lot more in store for BreakBase, including a ton of other games!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/06/introducing-breakbase-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook Psychic Mode</title>
		<link>http://www.mjcblog.net/2011/05/facebook-psychic-mode/</link>
		<comments>http://www.mjcblog.net/2011/05/facebook-psychic-mode/#comments</comments>
		<pubDate>Wed, 18 May 2011 19:31:15 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=205</guid>
		<description><![CDATA[One thing that I&#8217;ve always enjoyed about the Pidgin chat client is the Psychic Mode plugin. This plugin basically detects when you receive an event from a given chat network that another user is typing a message to you. If you do not have a chat window open with that user, one will suddenly appear [...]]]></description>
			<content:encoded><![CDATA[<p>One thing that I&#8217;ve always enjoyed about the <a href="http://pidgin.im/">Pidgin</a> chat client is the Psychic Mode plugin. This plugin basically detects when you receive an event from a given chat network that another user is typing a message to you. If you do not have a chat window open with that user, one will suddenly appear when plugin is triggered with the message &#8220;You feel a disturbance in the force&#8230;&#8221;.</p>
<p>After a little poking around on Facebook, I realized it&#8217;s pretty easy to add the same functionality into Facebook chat. I decided to write a simple Chrome extension to prototype the idea. You need to enable <a href="http://code.google.com/chrome/extensions/experimental.html">experimental extensions</a> for any of the following code to work.</p>
<pre><code>
experimental.webInspector.resources.onFinished.addListener(function(resource){
  if (resource.request.url.match(/channel\.facebook\.com/)) {
    resource.getContent(function(content, encoding){
      if (content == null) return;

      if (content.match(/"type":"typ"/) &amp;&amp; content.match(/"st":1/)) {
        var from = content.match(/"from":\d+/);

        experimental.webInspector.log('You sense a disturbance in the force from... ' + /\d+/.exec(from)[0]));

      }
    });
  }
});
</code></pre>
<p>&nbsp;</p>
<p>When someone is typing a message to you, their browser will make a POST to &#8216;ajax/messaging/typ.php&#8217;. Facebook will then send your browser a message that contains an object with a &#8216;type&#8217; property of &#8216;typ&#8217; and &#8216;st&#8217; property of 1. This extension simply looks for requests made to Facebook and attempts to find responses that meet said criteria.</p>
<p>This idea could perhaps be further flushed out via Firefox extensions. Chrome&#8217;s extension design and APIs make such a thing difficult (actively viewing requests and responses made by the browser). Such things are easier with Firefox where less restrictions and sandboxing for extensions are in place. Such an extension should likely even open the the chat tab with the target user (and of course display the &#8216;You sense a disturbance in the force from&#8230;&#8217; message).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/05/facebook-psychic-mode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing a New jQuery Google Maps Script</title>
		<link>http://www.mjcblog.net/2011/04/introducing-a-new-jquery-google-maps-script/</link>
		<comments>http://www.mjcblog.net/2011/04/introducing-a-new-jquery-google-maps-script/#comments</comments>
		<pubDate>Fri, 15 Apr 2011 01:58:56 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[maps]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=181</guid>
		<description><![CDATA[This script is similar to the one I wrote a few years back. This time however, it&#8217;s a jQuery plugin. Head on over to the github project for more details.]]></description>
			<content:encoded><![CDATA[<p>This script is similar to the one I wrote a few years back. This time however, it&#8217;s a jQuery plugin. Head on over to the <a href="https://github.com/mikeycgto/jquery.map.js">github project</a> for more details.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2011/04/introducing-a-new-jquery-google-maps-script/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flash ExternalInterface Internet Explorer Gotcha</title>
		<link>http://www.mjcblog.net/2010/03/flash-external-interface-addcallback-gotcha-in-internet-explorer-2/</link>
		<comments>http://www.mjcblog.net/2010/03/flash-external-interface-addcallback-gotcha-in-internet-explorer-2/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 02:11:10 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[internet-explorer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[microsoft]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=154</guid>
		<description><![CDATA[Just learned this one the hard way. Apparently in Internet Explorer, a Flash application cannot use the &#8220;ExternalInterface&#8221; to add a callback named &#8216;play&#8217;. This list of reserved words also includes &#8216;stop&#8217;, &#8216;tags&#8217;, &#8216;item&#8217; and possibly others. Makes sense, but it took me a while to figure this one out since it is does not [...]]]></description>
			<content:encoded><![CDATA[<p>Just learned this one the hard way. Apparently in Internet Explorer, a Flash application cannot use the &#8220;ExternalInterface&#8221; to add a callback named &#8216;play&#8217;. This list of reserved words also includes &#8216;stop&#8217;, &#8216;tags&#8217;, &#8216;item&#8217; and possibly others.</p>
<p>Makes sense, but it took me a while to figure this one out since it is does not seem to be documented anywhere.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2010/03/flash-external-interface-addcallback-gotcha-in-internet-explorer-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Full Tree Selects via Materialized Paths</title>
		<link>http://www.mjcblog.net/2009/03/full-tree-selects-via-materialized-paths/</link>
		<comments>http://www.mjcblog.net/2009/03/full-tree-selects-via-materialized-paths/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 18:51:45 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.mjcblog.net/?p=112</guid>
		<description><![CDATA[At my internship I have been working on this really awesome in-house analytics systems.  One of the database tables used in this project behaves as a self-referential tree.  Since I am using Ruby on Rails for this project, I decided to go with the acts_as_tree plugin on this particular model.  This plugin adds various tree [...]]]></description>
			<content:encoded><![CDATA[<p>At my <a title="IMRE" href="http://www.imre.com" target="_blank">internship</a> I have been working on this really awesome in-house analytics systems.  One of the database tables used in this project behaves as a self-referential tree.  Since I am using Ruby on Rails for this project, I decided to go with the <a title="acts_as_tree Class Methods" href="http://api.rubyonrails.org/classes/ActiveRecord/Acts/Tree/ClassMethods.html" target="_blank">acts_as_tree</a> plugin on this particular model.  This plugin adds various tree related methods with a minimal requirement that a foreign key column named &#8220;parent_id&#8221; exists in the corresponding table.</p>
<p>This plugin functioned as expected and something can certainly be said for sheer simplicity that this particular tree structure employs.  The complication arose when my application called for a full select of all the descendants from a given node.  This particular tree structure doesn&#8217;t support an efficient way to grab all of the corresponding descendant records.</p>
<p><span id="more-112"></span></p>
<p>So I decided to implement a <a title="Materialized Path" href="http://www.dbazine.com/oracle/or-articles/tropashko4" target="_blank">Materialized Path</a> on top of my simple tree structure by adding a path column to the table. Here is a sample of what my tree table would look like.  For the sake of the example, we&#8217;ll call this table Nodes:</p>
<table style="margin: 0 auto; text-align: center;" border="0" cellspacing="4" cellpadding="2">
<tbody>
<tr>
<th>id</th>
<th>parent_id</th>
<th>path</th>
</tr>
<tr>
<td>1</td>
<td>NULL</td>
<td></td>
</tr>
<tr>
<td>2</td>
<td>NULL</td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>N1</td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td>N2</td>
</tr>
<tr>
<td>5</td>
<td>3</td>
<td>N1.N3</td>
</tr>
<tr>
<td>6</td>
<td>4</td>
<td>N2.N4</td>
</tr>
<tr>
<td>7</td>
<td>6</td>
<td>N2.N4.N6</td>
</tr>
</tbody>
</table>
<p>Each path is constructed by taking a given node&#8217;s parent path and concatenating it with the parent ID.  I like to prefix each ID number with the first letter of the models name, hence the &#8220;N&#8221; from &#8220;Nodes&#8221;.  Keep in mind that any piece of unique data can be used, it doesn&#8217;t need to be the ID number.  My analytics system uses an alternative string of unique data for the materialized path.</p>
<p>Now grabbing all of the descendants for node 2 is quite simple really; here&#8217;s a sample SQL query:</p>
<p><code>SELECT * FROM nodes WHERE path LIKE "N2%";</code></p>
<p>The Rails code for adding this functionality is equally simple.  A <em>before_create</em> callback in the given model will do the trick.  Here is a quick sample:</p>
<pre><code>before_create do |n|
  self.path = "#{n.parent.path}N#{n.parent.id}"
end</code></pre>
<p>Also note, that depending on the data type used for the path column, you maybe limited on how deep the descendants can go.  For instances, a varchar(255) column only allows 255 characters, so if each node takes up an average 5 characters we&#8217;re limited to 51 nodes.  While this may seem like a lot, it&#8217;s something to just keep in mind when implementing this solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mjcblog.net/2009/03/full-tree-selects-via-materialized-paths/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

