<?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/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>MettaProgramming &#187; Ruby</title>
	<atom:link href="http://mettadore.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://mettadore.com</link>
	<description>Thoughts on Software and Technology</description>
	<lastBuildDate>Mon, 09 Apr 2012 19:11:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Bundle update &#8220;killed:&#8221; Watch those log files in your gems!</title>
		<link>http://mettadore.com/ruby/bundle-update-killed-watch-those-log-files-in-your-gems/</link>
		<comments>http://mettadore.com/ruby/bundle-update-killed-watch-those-log-files-in-your-gems/#comments</comments>
		<pubDate>Mon, 09 Apr 2012 19:11:59 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=1028</guid>
		<description><![CDATA[Today was supposed to be a normal day. A simple pull-request merge, an automated Jenkins build, and then a database migration. What followed instead was a search for the cause of a build failure– or, rather, the cause of a ruby gem that was causing the build failure. The Problem The only hint I had [...]]]></description>
			<content:encoded><![CDATA[<p>Today was supposed to be a normal day. A simple pull-request merge, an automated Jenkins build, and then a database migration.</p>
<p>What followed instead was a search for the cause of a build failure– or, rather, the cause of a ruby gem that was <em>causing</em> the build failure.</p>
<h3>The Problem</h3>
<p>The only hint I had to go on was this message in my Jenkins console:</p>
<pre class="brush: bash; title: ; notranslate">
Installing acts_permissive (0.3.2) /tmp/hudson7424891008093103684.sh: line 5: 12423
Killed
bundle
Build step 'Execute shell' marked build as failure
</pre>
<p>It couldn&#8217;t install the gem? Why? To the console:</p>
<pre class="brush: bash; title: ; notranslate">
jenkins@li128-183:~/workspace/musicstand
$ bundle update acts_permissive
Fetching source index for http://rubygems.org/
Using rake (0.9.2.2)
Using RedCloth (4.2.9)
...

NoMemoryError: failed to allocate memory
An error occured while installing acts_permissive (0.3.2), and Bundler cannot continue.
Make sure that `gem install acts_permissive -v '0.3.2'` succeeds before bundling.
</pre>
<p>What the what? Sadly, trying it manually was no help:</p>
<pre class="brush: bash; title: ; notranslate">
jenkins@li128-183:~/workspace/musicstand
$ gem install acts_permissive -v '0.3.2'
Killed
</pre>
<p>That&#8217;s it. Nothing else.</p>
<h3>The Investigation</h3>
<p>Luckily<sup><a href="http://mettadore.com/ruby/bundle-update-killed-watch-those-log-files-in-your-gems/#footnote_0_1028" id="identifier_0_1028" class="footnote-link footnote-identifier-link" title="or, unluckily, as the case may be">1</a></sup> I am the writer of the Gem in question. <a href="http://rubygems.org/gems/acts_permissive">ActsPermissive</a> is an instance-specific permissions system based on &#8220;circles of trust&#8221; (a bit like Google+ circles).</p>
<p>I went to my dev folder for the gem and explored it. Nothing seemed out of the ordinary. So I created a new gemset and ran &#8220;bundle install&#8221; forcing an installation of acts_permissive. It installed fine; however, I did notice that Bundler seemed to &#8220;pause&#8221; while installing it. On a hunch, I went to look at what the size of the .gem file was.</p>
<h3>The Solution</h3>
<p>Embarrassing as it is, the .gem file weighed in at a whopping 23M. That&#8217;s just ridiculous for a few text files! Further investigation showed me that my development directory was a full Gig! What the what?</p>
<p>Log files.</p>
<p>Without thinking, I was including the spec/dummy rails application, which contains a log directory, and log/test.log was nearly a gigabyte in size! Consequently, that was all getting packaged up, and then this 1G gem was trying to be compressed on the server and borking because of failed memory!</p>
<p>Lazy, John!</p>
<p>I had the normal &#8220;s.test_files = Dir["spec/**/*"] line in my gemspec, but need to exclude some files. The &#8220;test_files&#8221; attribute is an array, thus, I added the following lines to my .gemspec:</p>
<pre class="brush: ruby; title: ; notranslate">
  s.test_files = Dir[&quot;spec/**/*&quot;]
  s.test_files.delete(&quot;spec/dummy/log&quot;)
  s.test_files.delete(&quot;spec/dummy/log/development.log&quot;)
  s.test_files.delete(&quot;spec/dummy/log/test.log&quot;)
</pre>
<p>This dropped the .gem file back to a few kilobytes, which is all it should ever be. </p>
<h3>Coda</h3>
<p>It took a bit of detective work, but the &#8220;bundle update &#8216;killed&#8217;&#8221; problem was a crisis averted. This would&#8217;ve been grueling to troubleshoot if I didn&#8217;t own the acts_permissive gem. However, in the interest of helping others, it can be pretty easy to at least rule this problem out if your &#8216;gem install&#8217; or &#8216;bundle update&#8217; fails mysteriously. Grab the .gem file from RubyGems and check the size. If it&#8217;s crazy huge like acts_permissive was, then you might just be filling up RAM when it&#8217;s extracted.</p>
<ol class="footnotes"><li id="footnote_0_1028" class="footnote">or, unluckily, as the case may be</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/bundle-update-killed-watch-those-log-files-in-your-gems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Redis-backed acts_as_follower gem</title>
		<link>http://mettadore.com/ruby/a-redis-backed-acts_as_follower-gem/</link>
		<comments>http://mettadore.com/ruby/a-redis-backed-acts_as_follower-gem/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 16:23:01 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=1009</guid>
		<description><![CDATA[I usually start blog-based introductions to gems and libraries that I write with a narrative. Lately, however, I&#8217;ve been getting busier keeping up with the work I need to do for clients and that I need to do for my startup. So I&#8217;ll leave the narrative to a minimum, a very short question. You love [...]]]></description>
			<content:encoded><![CDATA[<p>I usually start blog-based introductions to gems and libraries that I write with a narrative. Lately, however, I&#8217;ve been getting busier keeping up with the work I need to do for clients and that I need to do for my startup. So I&#8217;ll leave the narrative to a minimum, a very short question.</p>
<p>You love the acts_as_follower gem, right? Sure, everyone does. Wouldn&#8217;t it be better if it was based in Redis? Sure, of course it would.</p>
<p>This weekend I found the great <a href="https://github.com/agoragames/amico">Amico gem</a>, a low-level Ruby gem for Redis backed followers, and I decided to create <a href="https://github.com/mettadore/acts_as_amico">Acts_as_Amico</a>, a Rails injectable gem that uses that back-end ability, so now you can have a followers gem that is completely in Redis right in your Rails app.</p>
<p>The code has full-ish, but ever expanding, documentation on the Github page, but here&#8217;s a quick rundown</p>
<h3>ActiveRecord Objects</h3>
<pre class="brush: ruby; title: ; notranslate">
class User &lt; ActiveRecord::Base
 acts_as_amico
end

usera = User.create
userb = user.create

usera.follow! userb
=&gt; nil

usera.following? userb
 =&gt; true
</pre>
<h3>Advanced Usage</h3>
<pre class="brush: plain; title: ; notranslate">
class Admin &lt; ActiveRecord::Base
  acts_as_amico :amico_key =&gt; :name
  validates_uniqueness_of :name  # -&gt; do this or be sorry
  validates_presence_of :name # -&gt; this too, you've been warned
end

usera = User.create

puts usera.id
 =&gt; 18

admin = Admin.create :name =&gt; &quot;frank&quot;

usera.follow! admin
 =&gt; nil

admin.follow! usera
 =&gt; [1, 1]

admin.followers
 =&gt; [&quot;18&quot;]

usera.followers
 =&gt; [&quot;frank&quot;]
</pre>
<h3>ActiveResource Objects</h3>
<pre class="brush: ruby; title: ; notranslate">
class RestObject &lt; ActiveResource::Base
  self.site = &quot;http://mettadore.com/junk&quot;
  acts_as_amico :amico_key =&gt; :title
end

usera = User.create

rest_object = RestObject.find(123)

rest_object.title
 =&gt; &quot;Bread and Circus&quot;

usera.follow! rest_object

usera.following? rest_object
 =&gt; true

usera.following
 =&gt; [&quot;Bread and Circus&quot;]
</pre>
<h3>Issues</h3>
<p>I have every expectation that there will be problems and bugs. If you find one, please don&#8217;t hesitate to <a href="https://github.com/mettadore/acts_as_amico/issues">file an issue if</a> you&#8217;re on Github, or <a href="http://johnmetta.com/+">send me a message on Google+</a> if you&#8217;re not.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/a-redis-backed-acts_as_follower-gem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[Redis Gems]]></series:name>
	</item>
		<item>
		<title>Rails: SQL Injection over Configuration</title>
		<link>http://mettadore.com/analysis/rails-sql-injection-over-configuration/</link>
		<comments>http://mettadore.com/analysis/rails-sql-injection-over-configuration/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 17:59:50 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Miscellany]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[convention]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[SQL injection]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=991</guid>
		<description><![CDATA[It was an interesting weekend for the Github team, the Rails core team, and lots of Rails users who worked at all through the weekend. There are a lot of details about the weekend to discuss, but my main discussion point is one of philosophy and intention of the Rails project. We&#8217;ll get to that [...]]]></description>
			<content:encoded><![CDATA[<p>It was an interesting weekend for the Github team, the Rails core team, and lots of Rails users who worked at all through the weekend. There are a lot of details about the weekend to discuss, but my main discussion point is one of philosophy and intention of the Rails project. We&#8217;ll get to that towards the end. First, a bit of background.</p>
<h3>Hacking Github</h3>
<p>This weekend, a Github user named <a href="https://github.com/homakov">Egor Homakov</a> hacked Github in such a way that allowed him to <a href="https://github.com/rails/rails/commit/b83965785db1eec019edf1fc272b1aa393e6dc57">commit directly to the Rails core</a> project. Since Homakov is not a Rails team member, this is a really big deal.</p>
<p>Since this happened, there&#8217;s been a lot of talk about the Rails core being fundamentally insecure. In fact, <a href="https://github.com/rails/rails/issues/5239">Homakov has been harping on this for at least 1000 years</a>. A few days ago he filed an issue about a <a href="https://github.com/rails/rails/issues/5228">mass assignment vulnerability</a> in the Rails core, and later he illustrated this vulnerability by filing an <a href="https://github.com/rails/rails/issues/5239">issue report from the future</a>. He was illustrating that you can inject attributes into a Rails model with an HTTP request.</p>
<p>So, when no-one took him seriously, he took the next step. He created HTTP PUT requests adding his SSH key to a Rails core user id, then <a href="https://github.com/rails/rails/commit/b83965785db1eec019edf1fc272b1aa393e6dc57">pushed a commit directly to Rails core</a>.</p>
<h3>How to Hack Rails</h3>
<p>It turns out that Rails apps, by default, are easy to hack. Peter Nixey wrote a very detailed post about <a href="https://gist.github.com/1978249">how Homakov hacked Github and the one line of code that could have prevented it</a>, so if you want the full details, read there. The summary is much shorter.</p>
<p>Let&#8217;s create a simple User model which has two attributes, <code>name</code> and <code>role</code>. By default, every attribute of every model can be modified by using <code>update_attributes</code>. We all know this, and we&#8217;ve known it for a while. What it means is that any User, even if they don&#8217;t have permission, can update their own role. Imagine if I log in to our example app and submit a PUT request to the UsersController with the package <code>{'params': {'id': 23, 'role': 'superadmin'} }</code>. By default, the app will accept this and update the user with the new role.</p>
<p>This is exactly what Homakov did. He sent an HTTP request to Github and used update_attributes to change the Github database. All of this could, he argued, be prevented by adding attr_accessor to the User model.</p>
<h3>Rails: Convention over <del>Configuration</del> Security</h3>
<p>Now, the philosophical point I want to make about this is that the Rails core team seems to be ignoring their own mantra. All of us know that Rails adheres strongly to the <a href="http://en.wikipedia.org/wiki/Convention_over_configuration">Convention over Configuration</a> design pattern. It&#8217;s a pattern that Rails users are taught from day one. In fact, it&#8217;s embedded in the framework&#8217;s <em>name</em>.<sup><a href="http://mettadore.com/analysis/rails-sql-injection-over-configuration/#footnote_0_991" id="identifier_0_991" class="footnote-link footnote-identifier-link" title="Look, just stay on these rails and you&amp;#8217;ll move fast. We&amp;#8217;re not responsible for what happens if you go over there">1</a></sup></p>
<p>One of the outcomes of Convention over Configuration is that sensible defaults should be, well, sensible. The Rails core team feel strongly that attr_accessor should not be a default<sup><a href="http://mettadore.com/analysis/rails-sql-injection-over-configuration/#footnote_1_991" id="identifier_1_991" class="footnote-link footnote-identifier-link" title="Incidentally, I don&amp;#8217;t either, but you can set this as the default by using ActiveRecord::Base.send(:attr_accessible, nil), but this causes all sorts of problems">2</a></sup> and that security is the responsibility of the app developer. I agree that security is our responsibility, but disagree that the dominant Rails design-pattern-come-mantra supports this.</p>
<p>It&#8217;s almost as if no-one wants to say &#8220;Yeah, we should really take care of this.&#8221; Everyone is saying &#8220;You know, <em>you</em> should really take care of this.&#8221;</p>
<h3>Stop the world! We&#8217;ve found a SQL injection</h3>
<p>There&#8217;s a term that makes all software developers give pause: &#8220;SQL Injection.&#8221; It&#8217;s a phrase that keeps us lying awake at night, and gives us nightmares when we finally fall asleep. The idea that someone, using nothing more than a web browser, can change our database willy nilly. It&#8217;s a terrifying thought.</p>
<p>I can&#8217;t help but take an initial read of all the hubbub and think that we&#8217;re not giving it the importance that it&#8217;s due. Everyone sees a headline saying Rails has a &#8216;mass assignment vulnerability&#8217; and says to themselves &#8216;I should probably look into that at some point.&#8217; It&#8217;s too vague, to uncertain. To unemotional.<sup><a href="http://mettadore.com/analysis/rails-sql-injection-over-configuration/#footnote_2_991" id="identifier_2_991" class="footnote-link footnote-identifier-link" title="In fact, to be honest, that&amp;#8217;s how I was reading it.">3</a></sup></p>
<p>I have to assume that everyone would be treating this differently if we called it what it is. Imagine your thoughts (and actions) if you read a different headline, something like &#8220;Rails apps prone to SQL injection by default&#8221;</p>
<p>Don&#8217;t you think you&#8217;d get something done? You should, because that&#8217;s what we&#8217;re talking about. This is a path to SQL injection, full stop.</p>
<h3>Who owns this issue</h3>
<p>I love Ruby on Rails. Like Python, Scala, Node.js, and a host of other technologies that we have at our disposal, Ruby&#8217;s web framework makes being a developer both powerful and fun. There&#8217;s so much we can do– and so much we can do <em>very quickly</em>. But there&#8217;s a cost to pay. Convention over Configuration is a good thing, but we can&#8217;t expect people to learn fast, develop fast– create fast– if we don&#8217;t respect the logical outcome of that philosophy.</p>
<p>That outcome is this: We, Rails developers, understand that we are responsible for our security; however, we also <em>believe</em> in you, the Rails core team. We trust you. We believe it when you tell us to follow &#8220;Convention over Configuration,&#8221; and so we naturally believe that the defaults you give us will be a safe, or at least not horribly, dangerously wrong. We, all of us– developers and Rails core team both– can&#8217;t have it both ways. We are telling ourselves to follow Convention over Configuration, but we&#8217;re also telling ourselves that SQL Injection is <em>a viable convention</em>, thus, that we have <em>security as a configuration</em>.</p>
<p>Now, personally, I don&#8217;t believe that attr_accessor belongs in the model– or at least that security from view-based actions belongs in the model. Rails is an MVC framework, and therefore I don&#8217;t like forcing myself to define my <em>model</em> based on actions in the <em>view</em>. I don&#8217;t want my view owning control of my model that way. I think the controller should manage these permissions and there are <a href="http://jonathanleighton.com/articles/2011/mass-assignment-security-shouldnt-happen-in-the-model/">others who feel the same</a>. In fact <a href="https://gist.github.com/1974187">Yehuda Katz argues this as well</a>.</p>
<p>Still, the overall question remains: How can we reconcile the mantra of Convention over Configuration if we support the standard of dangerous insecurity by convention?</p>
<ol class="footnotes"><li id="footnote_0_991" class="footnote">Look, just stay on these rails and you&#8217;ll move fast. We&#8217;re not responsible for what happens if you go over there</li><li id="footnote_1_991" class="footnote">Incidentally, I don&#8217;t either, but you can set this as the default by using <code>ActiveRecord::Base.send(:attr_accessible, nil)</code>, but this causes all sorts of problems</li><li id="footnote_2_991" class="footnote">In fact, to be honest, that&#8217;s how I was reading it.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/analysis/rails-sql-injection-over-configuration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Web App Went Live Today</title>
		<link>http://mettadore.com/analysis/a-web-app-went-live-today/</link>
		<comments>http://mettadore.com/analysis/a-web-app-went-live-today/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 21:25:26 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Miscellany]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=967</guid>
		<description><![CDATA[A new web app went live today, and I shed a tear. The Power of Good Questions Some history. Years ago, I was starting to question my decision to become a hydrologist. Not because I hated hydrology, I did– and still do– deeply love it, but because I couldn&#8217;t find a job. Since I&#8217;d been [...]]]></description>
			<content:encoded><![CDATA[<p>A new web app went live today, and I shed a tear.</p>
<h3>The Power of Good Questions</h3>
<p>Some history.</p>
<p>Years ago, I was starting to question my decision to become a hydrologist. Not because I hated hydrology, I did– and still do– deeply love it, but because I couldn&#8217;t find a job. Since I&#8217;d been a programmer for 20+ years (indeed, I programmed all the way through 10 years in the sciences), I decided to see what options were out there in that field.</p>
<p>So I interviewed for this software development company. I was nervous because I hadn&#8217;t actually <em>worked</em> as a programmer in a long time. My title had been &#8220;researcher&#8221; and &#8220;scientist&#8221; for a decade. Even though I&#8217;d been programming that entire time, I was nervous about being labeled as a &#8220;wannabe.&#8221;</p>
<p>My interviewer saw through that nervousness right away and immediately started asking me questions that were not the basic &#8220;do you actually know programming&#8221; but were much more geared toward &#8220;what do you think of this subtle programming construct.&#8221;  It was, without a doubt, the best interview experience I ever had, and made me respect the interviewer and want to work with him even if not at this job– which I didn&#8217;t even get.</p>
<p>I never forgot that interview.</p>
<h3>What Goes Around</h3>
<p>Fast forward a few years, and last year I happened to see that same interviewer at the coffee shop. He said that he&#8217;d just left his last job and was looking for work. That, to me, was a wide open door. Finally, a chance to work with this guy!</p>
<p>&#8220;Really,&#8221; I said, &#8220;It&#8217;s not much, but I&#8217;ve got some Ruby work I could use some help with for my company if you&#8217;re interested&#8221;</p>
<p>&#8220;I don&#8217;t know Ruby, I&#8217;ve been learning a little bit, but I can&#8217;t do work in it.&#8221;</p>
<p>&#8220;Tell you what, work with me. I&#8217;ll help you learn Ruby while you do small bits of work on my site. Fair trade?&#8221;</p>
<p>As I suspected from this now barely remembered interview so long ago, he was a sharp tack and things progressed fast enough that he never even did any work on my site. Rather, I took another contract that was a wee bit too big for me, and brought him on as a sub. And so, finally, I was working with this guy, and helping him learn Ruby, and getting him <em>paid</em> to do it.</p>
<h3>A Favor, Returned</h3>
<p>A couple months later, I got contacted by another company who wanted me to create a web app. I was just too busy, so I brought this fellow to the first meeting. My response was, basically, &#8220;I&#8217;m too busy to do this, but I can speak from experience that this fellow here is a good candidate. I&#8217;ll let you take it from here.&#8221; And I walked away. Now, here we are, a couple months after that, and <a href="http://mylunchin.com">MyLunchIn.com</a> has launched for our local restaurant Nora&#8217;s Table. It&#8217;s another Rails app that he created, start to finish, entirely free of my involvement.</p>
<p>I don&#8217;t know I started to cry when I placed my first lunch order today. I didn&#8217;t create that site, and honestly, I didn&#8217;t teach this guy Ruby– I just happened to be around while he was teaching himself. But it still feels good.</p>
<p>All those years ago, I was a scientist scared that I wouldn&#8217;t be accepted by &#8220;serious&#8221; developers and I was. It feels good to think that I brought some happiness back to that person, a favor returned. It just feels like this new website is part of a rising tide that floats all of our boats when we work together, when we look out for each other. When we remember a good conversation.</p>
<p>I&#8217;m on my way now to pick up my first ever lunch ordered on this new site. It&#8217;ll be the best tasting lunch I&#8217;ve had in a while.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/analysis/a-web-app-went-live-today/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Polymorphic :has_many, :through in Rails modules</title>
		<link>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/</link>
		<comments>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 19:28:49 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=895</guid>
		<description><![CDATA[[Update: Stephan Wehner actually showed me how to get this working (see his branch). Something else was wrong in the program I was actually using, which went away when I built this simplified version- I just never really tested with the simplified version. Thus, this post is now pointless. Thanks Stephan.] Recently, I had need [...]]]></description>
			<content:encoded><![CDATA[<h3>[Update: <a href="http://stephan.sugarmotor.org/">Stephan Wehner</a> actually showed me how to get this working (see <a href="https://github.com/johnmetta/polymorphic_plugin/tree/class-name">his branch</a>). Something else was wrong in the program I was actually using, which went away when I built this simplified version- I just never really tested with the simplified version. Thus, this post is now pointless. Thanks Stephan.]</h3>
<p>Recently, I had need to create a plugin that held a polymorphic :has_many, :through relationship. I spent a day or so trying to get this to work, only to realize that it is essentially impossible to do inside a pluggable Rails module, but possible if you templatize the classes.</p>
<h3>PolymorphicPlugin Example Project</h3>
<p>There&#8217;s a <a href="http://stackoverflow.com/questions/8130537/polymorphic-has-many-through-as-module-in-rails-3-1-plugin">StackOverflow thread</a> that describes this problem and the solution a bit; however, Based on the difficulty, and the fact that I couldn&#8217;t find any documentation specific to this problem, I figured I&#8217;d write it up as an example, and create a PolymorphicPlugin gem to illustrate it better.</p>
<p>The <a href="https://github.com/johnmetta/polymorphic_plugin/tree/side-module">PolymorphicPlugin inside-module branch</a> is an example of the way you&#8217;d distribute a pluggable Rails module with all classes contained in the module. The generator only creates a migration in the Rails project.</p>
<p>The <a href="https://github.com/johnmetta/polymorphic_plugin/tree/outside-module">PolymorphicPlugin outside-module</a> branch is an example of the way you&#8217;d distribute a pluggable Rails module in such a way that the generator creates a migration in <em>and also copies model files to</em> the Rails project.</p>
<h3>Problem Description</h3>
<p>The idea is that there&#8217;s an &#8220;acts_as&#8221; like plugin that I want to add to my Rails models:</p>
<pre class="brush: ruby; title: ; notranslate">
module PolymorphicPlugin
  module PolymorphicHolder

    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      def holds_things
        has_many :thing_groupings, :as =&gt; :thingable
        has_many :things, :through =&gt; :thing_groupings
        include PolymorphicPlugin::PolymorphicHolder::InstanceMethods
      end
    end

    module InstanceMethods

      def has_things?
        true
      end

    end
  end
end
</pre>
<p>You can see that anything that calls <code>holds_things</code> should have a :has_many relationship with <code>Thing</code> through the <code>ThingGrouping</code> join table. This is a standard paradigm for a polymorphic :has_many, :through relationship.</p>
<p>Basically, I want to do this:</p>
<pre class="brush: ruby; title: ; notranslate">
class User &lt; ActiveRecord::Base
  holds_things
end

class Admin &lt; ActiveRecord::Base
  holds_things
end

user = User.new
user.has_things? -&gt; true

admin = Admin.new
admin.has_things? -&gt; true
</pre>
<div id="attachment_897" class="wp-caption alignleft" style="width: 210px"><a href="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.51.18-AM.png"><img src="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.51.18-AM-300x283.png" alt="" title="Screen Shot 2011-11-15 at 10.51.18 AM" width="200" class="size-medium wp-image-897" /></a><p class="wp-caption-text">inside-module plugin layout</p></div>
<h3>The failing case</h3>
<p>Seems pretty simple, right?</p>
<p>Turns out it&#8217;s not. Take a look at the directory layout that I tried to use. This seems like a standard for a gemmable plugin. The model files are contained in the gem library, and accessed as part of the module. When you use <code>gem 'polymorphic_plugin'</code>, the only thing that gets copied to your Rails project is the migration file. Nice and clean.</p>
<p>Unfortunately, that doesn&#8217;t work. If you clone this branch and run <code>rake test</code> you&#8217;ll get exceptions. Specifically, a <code>NameError: uninitialized constant User::ThingGrouping</code> because our <code>User</code> model, by extending the <code>PolymorphicHolder</code> module, doesn&#8217;t have access to this unknown model called <code>ThingGrouping</code>.</p>
<p>And no, using things like <code>:class_name</code> and <code>:source</code> were no help. <a href="http://stackoverflow.com/questions/8130537/polymorphic-has-many-through-as-module-in-rails-3-1-plugin">I tried everything, or seemingly everything</a>. Nothing would make this work.</p>
<div id="attachment_898" class="wp-caption alignleft" style="width: 210px"><a href="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.52.40-AM.png"><img src="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.52.40-AM-300x281.png" alt="" title="Screen Shot 2011-11-15 at 10.52.40 AM" width="200" class="size-medium wp-image-898" /></a><p class="wp-caption-text">outside-module plugin layout</p></div>
<h3>The passing case</h3>
<p>That is until I pulled the models outside of the plugin module. </p>
<p>Take a look at the directory layout now and you&#8217;ll notice that the <code>Thing</code> and <code>ThingGrouping</code> models are no longer in the plugin&#8217;s lib directory. Moving them to the templates directory is the unfortunate answer.</p>
<p>I say &#8220;unfortunate&#8221; because this means that the models need to be distributed by copying them to the Rails project. In other words, there&#8217;s a line in my <code>PolymorphicPluginGenerator</code> that reads: <code>    template "thing.rb", File.join('app/models', "thing.rb")</code>. In other words: Copy the <code>Thing</code> model into this project so it can be accidentally futzed with by users and maybe, if we&#8217;re lucky, cause some interesting name collisions.</p>
<p><code>Thing</code> and <code>ThingGroup</code> are no longer contained inside my PolymorphicPlugin module. They are top-level classes equivalent to anything generated with <code>rails generate model</code>. Not a solution that I&#8217;m fond of, but one that passes my tests. We can at least have a polymorphic :has_many, :through relationship now.</p>
<h3>Outcome</h3>
<p>Polymorphic :has_many, :through relationships are available in pluggable Rails modules, but it&#8217;s a bit of a kludge. You&#8217;ll need to make sure you name your polymorphic classes smartly to avoid name collisions with the calling Rails project. You&#8217;d hate to create a plugin with a model like <code>Book</code> only to find that <code>Book</code> already exists in someone&#8217;s Rails project!</p>
<p>I&#8217;d love to be proven wrong on this, by the way. Go ahead and <a href="https://github.com/johnmetta/polymorphic_plugin">grab the Github repository</a> and play with the inside-module branch. If you can make it work, I&#8217;ll buy you a beer!</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3.1 Gemmable Plugins with RSpec</title>
		<link>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/</link>
		<comments>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 19:41:27 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=888</guid>
		<description><![CDATA[I&#8217;ve had a bitch of a time lately getting the new Rails 3.1 plugin architecture to play nicely with RSpec. I actually gave up and coded an entire plugin with Test::Unit before finally figuring out a decent way to do it. Currently, the new Rails 3.1 mountable plugin architecture will not work with RSpec. There&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had a bitch of a time lately getting the new Rails 3.1 plugin architecture to play nicely with RSpec. I actually gave up and coded an entire plugin with Test::Unit before finally figuring out a decent way to do it.</p>
<p>Currently, the new Rails 3.1 mountable plugin architecture <a href="https://github.com/rspec/rspec-rails/issues/258">will not work with RSpec</a>. There&#8217;s a gem called <a href="https://github.com/josevalim/enginex">Enginex</a> that will work with RSpec, but it <a href="https://github.com/josevalim/enginex/issues/35">won&#8217;t work with Rails 3.1</a>. So it looks like you either get RSpec or Rails 3.1. What&#8217;s the deal?</p>
<p>Playing around, I figured out that combining the two will work:</p>
<pre class="brush: bash; title: ; notranslate">
$ gem install enginex
…
$ enginex my_plugin --test-framework=rspec
…
$ rails -v
Rails 3.1.1
$ rails plugin new stock_plugin --full
…
$ rm -rf my_plugin/spec/dummy
$ cp -r stock_plugin/test/dummy my_plugin/spec
</pre>
<p>After that, it&#8217;s just a matter of modifying my_plugin/spec/dummy/config/application.rb to require your gem, and clean up the spec_helper.rb file. I also changed the Gem files so that my_plugin.gemspec held the dependencies, and Gemfile just called that. This is the way the stock Rails 3.1 generator works. Enginex uses Gemfile as the canonical source, and I like the new way better.</p>
<p>Using this I&#8217;ve currently got a Rails 3.1 gemmable plugin with RSpec, Cucumber, Capybara, Spork, Guard, and Simplecov working just fine.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wrestling ActiveResource Associations</title>
		<link>http://mettadore.com/ruby/wrestling-activeresource-associations/</link>
		<comments>http://mettadore.com/ruby/wrestling-activeresource-associations/#comments</comments>
		<pubDate>Sat, 25 Jun 2011 01:13:50 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=830</guid>
		<description><![CDATA[I need to state up front that I don&#8217;t have a solution to this problem. Hopefully, I can iterate toward a solution- using this interim solution (discussed at the end). The basic problem that I&#8217;ve found is that ActiveResource is a great Rails model to inherit from, except when it isn&#8217;t. And it seems that [...]]]></description>
			<content:encoded><![CDATA[<p>I need to state up front that I don&#8217;t have a solution to <a href="http://stackoverflow.com/questions/6448135/has-many-through-with-activeresource-models">this problem</a>. Hopefully, I can iterate toward a solution- using this interim solution (discussed at the end).</p>
<p>The basic problem that I&#8217;ve found is that ActiveResource is a great Rails model to inherit from, except when it isn&#8217;t. And it seems that &#8220;when it isn&#8217;t&#8221; basically means &#8220;anytime you are using associations.&#8221; To be fair, associations don&#8217;t <em>always</em> break, it just turns out that my architecture illustrates exactly when they <em>do</em> break.</p>
<p>To lay out the situation, I have a backend server running Rails with three models, User, Service, and Groups. I have a Rails frontend server without a database hitting this (as well as other) backend servers.</p>
<h3>Backend</h3>
<pre class="brush: ruby; title: ; notranslate">class User  :members
  has_many :managed_groups, :class_name =&amp;gt; &quot;Group&quot;
  accepts_nested_attributes_for :managed_groups, :services, :groups
end

class Group  :members
  belongs_to :manager, :class_name =&amp;gt; &quot;User&quot;, :foreign_key =&amp;gt; :user_id
  accepts_nested_attributes_for :users  
end

class Service &amp;lt; ActiveRecord::Base
  belongs_to :user
end

class Member &amp;lt; ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end</pre>
<p>You can see it&#8217;s really basic setup. Users can have many Services, but Service can only have one User. By contrast, users can Manage many groups, and can belong to many Groups, while Groups can have many users who belong to it.</p>
<p>Users -&gt; Services is a basic :has_many relationship and Users -&gt; Groups is a :has_many, :through relationship. There is nothing complicated about this setup at all…</p>
<h3>Frontend</h3>
<p>…until you get to an ActiveResource frontend</p>
<pre class="brush: ruby; title: ; notranslate">class User &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end

class Group &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end

class Service &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end</pre>
<p>The frontend server sees all of these models as ActiveResources, which works fine if you&#8217;re accessing User.name, but which doesn&#8217;t work so well if you&#8217;re trying to access User.services because User.services doesn&#8217;t exist. ActiveResource simply doesn&#8217;t know anything about associations, so you have to work around a big problem.</p>
<h3>:include =&gt; :associated_model</h3>
<p>One easy way to make User.services available to ActiveResource is by including it in the UsersController. Here&#8217;s a sample UsersController#Show method on the backend:</p>
<pre class="brush: ruby; title: ; notranslate">def show
@user = User.find(params[:id])
  respond_to do |format|
    format.xml  { render <img src='http://mettadore.com/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml =&amp;gt; @user.to_xml(:include =&amp;gt; [:managed_groups, :services, :groups]) }
    format.json  { render :json =&amp;gt; @user.to_json(:include =&amp;gt; [:managed_groups, :services, :groups]) }
  end
end</pre>
<p>We just include a list of whatever associated objects we want to include in the returned user package. Easy enough. Starting up the Rails console on the frontend now allows you to access User.services. However, what if you tried the following:</p>
<pre class="brush: ruby; title: ; notranslate">
service = Service.create(:name =&amp;gt; &quot;Test Service&quot;)
user = User.first
user.services &amp;lt;&amp;lt; service
</pre>
<p>Turns out that we can&#8217;t do that. We get an exception that the User model expects a Service class, but was supplied with an IndifferentHash.</p>
<p>With a :has_many/:belongs_to relationship, this is easy to work around:</p>
<pre class="brush: ruby; title: ; notranslate">
service = Service.create(:name =&amp;gt; &quot;Test Service&quot;, :user_id =&amp;gt; User.first.id)
</pre>
<p>Of course, user_id is a &#8220;primitive&#8221; type, a direct attribute of Server. So we can force it by going to the other side of the relationship and set that attribute and not have a problem.</p>
<h3>:has_many, :through =&gt; :needles_in_your_eye</h3>
<p>Working around the :belongs_to issue was easy, working around :has_many, :through is as fun as… well, you get the idea.</p>
<p>The problem is that there&#8217;s no backdoor to setting the association. You simply can&#8217;t access an array of objects as an association through ActiveResource. Look at what we see when the frontend accesses the backend server with a PUT request at /users/1.xml:</p>
<pre class="brush: jscript; title: ; notranslate">
{&quot;user&quot;=&amp;gt;
  {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
   &quot;id&quot;=&amp;gt;1,
   &quot;name&quot;=&amp;gt;&quot;John Metta&quot;,
   &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
   &quot;managed_groups&quot;=&amp;gt;[],
   &quot;services&quot;=&amp;gt;[
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
      &quot;user_id&quot;=&amp;gt;1}
   ],
   &quot;groups&quot;=&amp;gt;[
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;user_id&quot;=&amp;gt;nil,
      &quot;users&quot;=&amp;gt;[
        {&quot;created_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC,
         &quot;id&quot;=&amp;gt;6,
         &quot;name&quot;=&amp;gt;&quot;Jefferey&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:59:36 UTC,
         &quot;id&quot;=&amp;gt;2,
         &quot;name&quot;=&amp;gt;&quot;George&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:05:13 UTC}
       ]
     },
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;name&quot;=&amp;gt;&quot;Site Admin&quot;,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;user_id&quot;=&amp;gt;nil,
      &quot;users&quot;=&amp;gt;[
        {&quot;created_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC,
         &quot;id&quot;=&amp;gt;6,
         &quot;name&quot;=&amp;gt;&quot;Jefferey&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:59:36 UTC,
         &quot;id&quot;=&amp;gt;2,
         &quot;name&quot;=&amp;gt;&quot;George&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:05:13 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
         &quot;id&quot;=&amp;gt;1,
         &quot;name&quot;=&amp;gt;&quot;John Metta&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC}
       ]
     }
   ]
  },
  &quot;id&quot;=&amp;gt;&quot;1&quot;}
</pre>
<p>Cats talking to dogs, here. They&#8217;d both be happy eating a squirrel, sure, but they just speak different languages.</p>
<p>Basically, the backend tries to find the &#8220;groups&#8221; and &#8220;services&#8221; properties on the User model. ActiveRecord expects groups to be, well Group objects- but it&#8217;s a Hash, not a Group. In order for this to work, those should be named &#8220;groups_attributes&#8221; and &#8220;services_attributes.&#8221;</p>
<p>This is basically telling me that ActiveRecord and ActiveResource basically don&#8217;t know how to talk to one another. What the hell was the Rails core team thinking?</p>
<p>ActiveResource should be patched to format it&#8217;s JSON string to use MODEL_attributes, right? Well, that would break a lot of stuff. ActiveResource is supposed to talk fine to my Scala backend server too, which it wouldn&#8217;t.</p>
<p>ActiveRecord should automatically treat MODEL: {ASSOCIATED_MODEL: …}} as something that can be converted to an ActiveRecord, right? I&#8217;m not sure of this one- it seems too possible to break things down the line that we didn&#8217;t expect.</p>
<p>So, you can do it from either direction without possibly horribly breaking something down the line.</p>
<p>Ahh, apparently the Rails core team was thinking &#8220;You know, we shouldn&#8217;t do this because we might horribly break something down the line.&#8221;</p>
<h3>Wrestling ActiveResource to the ground</h3>
<p>In order to fix this, I&#8217;ve added a simple hack to my UsersController on the backend. I say it&#8217;s simple because it&#8217;s pretty dumb. I say it&#8217;s a hack because I think it&#8217;s really ugly and inelegant&#8211; something I don&#8217;t expect from Rails.</p>
<p>Here&#8217;s the full UsersController#Update method on my backend server:</p>
<pre class="brush: ruby; title: ; notranslate">
  def update
    @user = User.find(params[:id])

    respond_to do |format|
      begin
        groups = []
        params[:user][:groups].each do |g|
          groups &amp;lt;&amp;lt; Group.find(g[:id])
        end
        params[:user][:groups] = groups
      rescue
      end

      begin
        services = []
        params[:user][:services].each do |s|
          services &amp;lt; @user.errors, :status =&amp;gt; :unprocessable_entity }
        format.json  { render :json =&amp;gt; @user.errors, :status =&amp;gt; :unprocessable_entity }
      end
    end
  end
</pre>
<p>As you can see, we grab that rogue IndifferentHash groups list and, basically, walk through it and find the local groups that correspond to the Group that&#8217;s in the list. This works- it allows ActiveResource to barely communicate with ActiveRecord. It&#8217;s no longer cats and dogs talking, it&#8217;s more like dogs and wolfs.</p>
<p>Yes, I know, wolves bite.</p>
<h3>One Model, One Resource</h3>
<p>This hack works, but it&#8217;s just that- A hack. If something seems this inelegant to me, then I have to question whether it is just that inelegant.</p>
<p>Today a friend mentioned that he&#8217;s never used accepts_nested_attributes_for. Never. He has never used nested resources like this because his strong philosophy is &#8220;One model, one resource.&#8221; I&#8217;m going to explore this for a few reasons, not the least of which is that I don&#8217;t think I want to pass the groups around inside the user if the user is a member of 3000 groups that we don&#8217;t care about. That&#8217;s just stupid.</p>
<p>Trying this method would mean that the User model on the frontend would require a groups method that would search the join table based on the user, and an additional add_group method which would go through the Group model to create a new group and somehow add that group to the users list of groups.</p>
<p>There&#8217;s a hole in my bucket, dear Liza, dear Liza, a hole in my bucket, dear Liza, a hole…</p>
<p>Really not sure how that would work&#8211; at least without some inclusion of my hack above. It seems like there&#8217;s just no way to get around this problem elegantly. I hope I&#8217;m wrong about that.</p>
<p>Someone please tell me I&#8217;m wrong.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/wrestling-activeresource-associations/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ruby, Chef, and Tilde- Home directory shortcut #fail</title>
		<link>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/</link>
		<comments>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/#comments</comments>
		<pubDate>Mon, 24 Jan 2011 21:17:17 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[chef]]></category>
		<category><![CDATA[knife]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=740</guid>
		<description><![CDATA[This should have been obvious to me, but wasn&#8217;t, so I want to make sure that it&#8217;s in the Googleverse in case someone steps into the same pit of idiocy that I did. The problem is that Ruby and Ruby-based tools like Chef are becoming so natural that they feel like they&#8217;re just part of [...]]]></description>
			<content:encoded><![CDATA[<p>This should have been obvious to me, but wasn&#8217;t, so I want to make sure that it&#8217;s in the Googleverse in case someone steps into the same pit of idiocy that I did.</p>
<p>The problem is that Ruby and Ruby-based tools like Chef are becoming so natural that they feel like they&#8217;re just part of the BASH shell. It took me a while to figure out the following error:</p>
<pre>
% knife cookbook create somename

/Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `initialize': No such file or directory -
 ~/Dev/Chef/chef-repo/cookbooks/sti-rewrites/recipes/default.rb (Errno::ENOENT)
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `open'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `create_cookbook'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:74:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife.rb:127:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/application/knife.rb:121:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/bin/knife:25
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/bin/knife:19:in `load'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/bin/knife:19
</pre>
<p>Because, no matter how much I confirmed that the directory existed, it still failed. Why?</p>
<p>Because Ruby, as anyone really thinking about it would naturally realize, doesn&#8217;t expand Bash shortcuts.</p>
<p>To wit: The following entry in my ~/.chef/knife.rb file:</p>
<pre>
...
cookbook_path [ '~/Dev/Chef/chef-repo/cookbooks', '~/Dev/Chef/chef-repo/cookbooks' ]
...
</pre>
<p>Which I generated by running a command at the bash shell:</p>
<pre>knife configure</pre>
<p>As anyone would expect, changing that line to:</p>
<pre>
...
cookbook_path [ '/Users/john/Dev/Chef/chef-repo/cookbooks', '/Users/john/Dev/Chef/chef-repo/cookbooks' ]
...
</pre>
<p>fixed the problem. D&#8217;oh!</p>
<p>As I use more Ruby-based server configuration tools, I think I need to be a bit more conscious of when I&#8217;m with the purview of the Bash shell, and when I&#8217;m not.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Creating a Robotic Secretary with Hazel, Automator, &amp; Ruby</title>
		<link>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/</link>
		<comments>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 23:08:24 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Miscellany]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[Hazel]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=606</guid>
		<description><![CDATA[If you&#8217;re on a Mac, and have to do a task more than once, then you need to use Hazel and Automator, full stop. I&#8217;m a consultant, and that means I work on multiple projects, and have to bill those projects. Recently, I began working on a contract that required weekly billing, using an Excel [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re on a Mac, and have to do a task more than once, then you need to use Hazel and Automator, full stop.</p>
<p>I&#8217;m a consultant, and that means I work on multiple projects, and have to bill those projects. Recently, I began working on a contract that required weekly billing, using an Excel spreadsheet that can&#8217;t be modified, and a signature from a project manager in another city. Talk about tedious! My workflow for just filling out a weekly timesheet is this:</p>
<ol>
<li>Use Freshbooks daily to track time</li>
<li>On Friday, open Freshbooks and pull the hours on that project</li>
<li>Open Excel (in VMWare) to update the read-only Master Timesheet file by changing the date, and adding my hours into the day slots
<ol>
<li>I can&#8217;t use Open Office or anything on the Mac since the formatting changes when I save it as an Excel file- I&#8217;ve tried a bunch of ways to do this, but as I usually have VMWare open to work in Visual Studio for this project anyway, I just use MS Excel on Windows</li>
</ol>
</li>
<li>Save the timesheet under another name</li>
<li>Drag the timesheet into another folder in my Dropbox (so that I have a record)</li>
<li>Open my email client and create an email to my project manager that says little more than &#8220;Timesheet, Cheers, -J&#8221;</li>
<li>Drag the timesheet into the email (I Google Mail&#8217;s ability to drag a file to attach!) and hit send</li>
<li>When he sends it back, it&#8217;s an attachment as an image- save the image to my project folder locally</li>
<li>Print out the image</li>
<li>Sign it (in blue pen, mind you)</li>
<li>Scan the signed copy</li>
<li>Move the scanned copy file to my local computer</li>
<li>Open a web browser to connect to their email system, which I&#8217;m supposed to use, but which is proxied, so I can&#8217;t use my normal email client.</li>
<li>Create another email to the timesheet recipient</li>
<li>Attach the file using the dialog boxes (Drag is not possible) and send it</li>
<li>Grab the timesheet original off my scanner and put in an envelope to mail to New York.</li>
</ol>
<p>Now, if you think about doing all of that, it&#8217;s not like it takes half the day. Still, it takes enough time that a good bit of my morning is lost to it. There&#8217;s not only the time spent &#8220;actively doing everything&#8221; but the lost time where I could have been concentrating on something like our object model or database abstraction layer, but which I&#8217;m distracted by simultaneously dealing with the timesheet issue. Anyone working in a &#8220;mental sphere&#8221; such as programming knows that a few seconds of distraction with something will pull you out of the mindset for 20 minutes or more.</p>
<p>Plus, there&#8217;s the added issue of this just being boring. It&#8217;s something a robot should be doing- or at least a secretary. More importantly, it&#8217;s something that could happen automatically! We programmers tend to get annoyed when things &#8220;should happen automatically&#8221; and they don&#8217;t. It is, in fact, why many of us became programmers.</p>
<h3>Enter Hazel</h3>
<p>For a while, I&#8217;ve been simplifying things a wee bit using <a href="http://www.noodlesoft.com/hazel.php">Hazel</a>. For those who don&#8217;t know, Hazel is a Mac program that watches a folder and performs actions based on the folder contents. I first heard about it on the <a href="http://macpowerusers.com/2010/04/mpu-025-geeking-out-with-hazel/">Mac Power Users</a> podcast and bought the software pretty much immediately following the podcast.</p>
<div id="attachment_608" class="wp-caption alignright" style="width: 310px"><a href="http://mettadore.com/files/2010/10/Screen-shot-2010-10-18-at-2.33.46-PM.png"><img class="size-medium wp-image-608" src="http://mettadore.com/files/2010/10/Screen-shot-2010-10-18-at-2.33.46-PM-300x122.png" alt="" width="300" height="122" /></a><p class="wp-caption-text">Hazel rules screen</p></div>
<p>Hazel is one amazing piece of time-saving software. It has a super simple graphical dialog box to let you set things like which folder, what attributes (&#8220;if files are older than&#8221; and &#8220;if file is a:&#8221; (e.g. movie, soundfile, pdf, etc) and &#8220;if the name contains:&#8221;) and what actions (Open, move, delete, archive, change name, import into iTunes, etc.) to perform on files in that folder.</p>
<p>One of the ways that I use it is on my desktop. If there are any pictures or movies on my desktop that are older than 1 day, Hazel takes them off my desktop and puts them on my remote hard drive, in appropriate folders, and simultaneously imports them into iTunes (I don&#8217;t have iTunes copy files to the local drive, so they&#8217;re watched from the remote drive).</p>
<p>When dealing with my timesheet, I have Hazel set up so that anything that goes into the &#8220;Timesheets&#8221; folder and is an Excel file gets automatically moved to a subfolder called &#8220;archive&#8221; and gets renamed with the pattern &#8220;John_Metta_&lt;date added&gt;.xls.&#8221; That way, I have an easily recognizable location and file to drag into an email to my project manager.</p>
<p>Using Hazel to automatically move, delete and organize your files can save you a lot of time. It&#8217;s tiny little chunks of time, sure, but it&#8217;s time. In reality, it&#8217;s saving you more the headache of having to do the same thing over and over again. Hazel is powerful, check it out.</p>
<h3>Add A Little Ruby</h3>
<p>Because I love Ruby, I decided to automate the creation of the Excel spreadsheet a bit. The Windows version of Ruby has the win32ole module, which can open and handle spreadsheets really easily. So I created a small script that opened a read-only version of the master timesheet spreadsheet and changed the date and the hours/day based on the arguments.</p>
<p>Here&#8217;s the whole script:</p>
<pre>require 'win32ole'

xl = WIN32OLE.new('Excel.Application')
xls = xl.Workbooks.open("c:\timesheets\Timesheet")
sheet = xls.Worksheets(1)

sheet.Cells(4,11).Value = ARGV[0]

#Time cell index
t = 6
ARGV.each_with_index do |a, i|
  sheet.Cells(10,t+i).Value = a
end

xls.SaveAs("Z:\john\Dropbox\Consulting Stuff\Nova\timesheets\timesheet")
xls.Close
xl.Quit</pre>
<p>With this, the command:</p>
<pre> C:timesheets$ ruby timesheet.rb "10/16" 0 0 8 7 6 7 8</pre>
<p>will create the correct timesheet for the week beginning 10/16, with the correct dates all lined up for the hours, and will save that timesheet to my Dropbox/timesheets directory- afterwhich Hazel will do the rest.<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_0_606" id="identifier_0_606" class="footnote-link footnote-identifier-link" title="There&amp;#8217;s actually an API library for Freshbooks in Ruby that is written  and maintained by Ben Curren at Outright.com, so you could pull the  hours straight from the project in a Ruby script- I decided against this  step">1</a></sup></p>
<h3>More with Automator</h3>
<div id="attachment_611" class="wp-caption alignright" style="width: 310px"><a href="http://mettadore.com/files/2010/10/automator-icon.png"><img class="size-medium wp-image-611" src="http://mettadore.com/files/2010/10/automator-icon-300x300.png" alt="" width="300" height="300" /></a><p class="wp-caption-text">Automator: More &quot;secretary&quot; than I&#039;d thought!</p></div>
<p>Earlier this week, I was still frustrated at the workflow of timesheets, however, because I still had a bunch of steps. Hazel was good at moving files and renaming them, but I still had to email them, print them, etc. So I decided to get my programming game on… then I decided that I didn&#8217;t even <em>need</em> to. Like all Macs, my Mac has Automator- a program that will create &#8220;workflows&#8221; and &#8220;applications&#8221; which basically amount to my own personal robotic secretary. Hazel can run both applications and Automator workflows on files, so I decided to give it a try.</p>
<h4><strong>Mailing to my PM</strong></h4>
<p>The first thing I do when I have my timesheet is move it to the timesheets folder where it gets renamed and archived so that I can send it to my PM. It would only be a single step to mail the renamed file. So I opened my Automator script and used the &#8220;create mail message,&#8221; &#8220;add attachment to open messages,&#8221; and &#8220;send mail&#8221; actions to create a script. Now, whenever a folder goes into Timesheets, it gets moved, renamed, <em>and</em> automatically mailed to my PM in one step!<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_1_606" id="identifier_1_606" class="footnote-link footnote-identifier-link" title="In full disclosure, the Automator script actually uses &amp;#8220;Save to a variable&amp;#8221; &amp;#8220;create new mail message&amp;#8221; &amp;#8220;get from variable&amp;#8221; &amp;#8220;add attachments&amp;#8221; and &amp;#8220;send mail&amp;#8221;&amp;#8211; in that order. For some reason, the &amp;#8220;add attachments&amp;#8221; phase was throwing an error otherwise.">2</a></sup></p>
<h4><strong>Printing and Signing</strong></h4>
<p>When my PM signs and mails it back it&#8217;s an image. So, I created another automator script to take any images with the name pattern &#8220;John_Metta_*&#8221; and the extension JPG in my &#8220;Downloads&#8221; directory and automatically move them to the &#8220;timesheets/images&#8221; directory and send them to the printer. That means all I have to do is open the email and click &#8220;download&#8221; and I&#8217;ll soon have a printed timesheet awaiting my signature. Sounds pretty secretary-like to me.</p>
<h4><strong>Mailing the final</strong></h4>
<p>My Canon all-in-one will scan automatically save files to a specific directory, so I could just set up Hazel to monitor that directory. The problem with this is that ANYTHING I scan will get processed. Rather than that, I&#8217;ve decided to have Hazel monitor that directory for a specific file name. Thus, when I scan any document, I see a dialog box on my screen prompting me to add a name. I can add a name in the rare occasions I want to scan something else. If I just hit &lt;enter&gt;, I&#8217;ve set Hazel up with another Automator script: Take the file, rename it with the pattern &#8220;John_Metta_Timesheet_&lt;date addedd&gt;&#8221;, mail it to the company as an attachment, and then throw the local copy in the trash (because Google Apps mail will store it for me).</p>
<h3>A Robotic Secretary</h3>
<p>The function of a secretary is to take care of everything that doesn&#8217;t absolutely need your action. A secretary should take care of everything in a &#8220;Do everything and let me just sign the paper.&#8221; That&#8217;s almost what I have now.</p>
<p>With this workflow, I&#8217;ve gone from 16 tedious steps to</p>
<ol>
<li>Track time daily in Freshbooks</li>
<li>Friday morning, while working, run the ruby command with my hours<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_2_606" id="identifier_2_606" class="footnote-link footnote-identifier-link" title="This automatically does everything through emailing my timesheet to my PM">3</a></sup></li>
<li>Work until lunch/break, before stopping, check my email (have an email from my PM waiting)</li>
<li>Click &#8220;download&#8221;<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_3_606" id="identifier_3_606" class="footnote-link footnote-identifier-link" title="This automatically files and prints the timesheet, it&amp;#8217;s just awaiting my signature">4</a></sup></li>
<li>Sign, scan, then hit enter</li>
</ol>
<p>That&#8217;s it!<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_4_606" id="identifier_4_606" class="footnote-link footnote-identifier-link" title="Well, I still have to mail it to New York, but that final step is a lot less annoying when it&amp;#8217;s not preceded by so much tedium!">5</a></sup></p>
<h3>Coda</h3>
<p>I highly suggest looking into combining Hazel, Automator, and any other talents you may bring to creating robotic secretaries for your automated tasks. This is just an example of a way you can take a morning&#8217;s worth of frustration and productivity vacuum and turn it into a few steps. Best of all, it took me about as long as two of these frustrating mornings to set everything up&#8211; meaning that it pays itself off in about half a month, on a year-long contract.<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_5_606" id="identifier_5_606" class="footnote-link footnote-identifier-link" title="I&amp;#8217;m sure this&amp;#8217;ll only get easier as more companies have APIs available. As I mentioned, I could probably have an automated task in Windows start the Ruby&nbsp; script and use output from a Freshbooks API query to automate step 2 above, meaning that I&amp;#8217;d do nothing until I got an email from my PM. However, I wanted the additional steps of adding my hours manually- more as a double check than anything.">6</a></sup></p>
<ol class="footnotes"><li id="footnote_0_606" class="footnote">There&#8217;s actually an API library for Freshbooks in Ruby that is written  and maintained by Ben Curren at Outright.com, so you could pull the  hours straight from the project in a Ruby script- I decided against this  step</li><li id="footnote_1_606" class="footnote">In full disclosure, the Automator script actually uses &#8220;Save to a variable&#8221; &#8220;create new mail message&#8221; &#8220;get from variable&#8221; &#8220;add attachments&#8221; and &#8220;send mail&#8221;&#8211; in that order. For some reason, the &#8220;add attachments&#8221; phase was throwing an error otherwise.</li><li id="footnote_2_606" class="footnote">This automatically does everything through emailing my timesheet to my PM</li><li id="footnote_3_606" class="footnote">This automatically files and prints the timesheet, it&#8217;s just awaiting my signature</li><li id="footnote_4_606" class="footnote">Well, I still have to mail it to New York, but that final step is a lot less annoying when it&#8217;s not preceded by so much tedium!</li><li id="footnote_5_606" class="footnote">I&#8217;m sure this&#8217;ll only get easier as more companies have APIs available. As I mentioned, I could probably have an automated task in Windows start the Ruby  script and use output from a Freshbooks API query to automate step 2 above, meaning that I&#8217;d do nothing until I got an email from my PM. However, I wanted the additional steps of adding my hours manually- more as a double check than anything.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Github as a Small-Scale CDN (w/Rails)</title>
		<link>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/</link>
		<comments>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 01:11:32 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=524</guid>
		<description><![CDATA[I love Github. Like tomato sandwiches, Celtic music, beer, and programming- Github is something that, try as I might, I just can&#8217;t make myself sick of.1 Recently, I took the Git survey, and it contained an interesting question along the lines of &#8220;What do you use Git for?&#8221; The answers were things like &#8220;configuration files&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://mettadore.com/files/2010/09/github-logo.png"><img class="alignleft size-full wp-image-525" src="http://mettadore.com/files/2010/09/github-logo.png" alt="" width="210" height="210" /></a>I love Github.</p>
<p>Like tomato sandwiches, Celtic music, beer, and programming- Github is something that, try as I might, I just can&#8217;t make myself sick of.<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_0_524" id="identifier_0_524" class="footnote-link footnote-identifier-link" title="I&amp;#8217;ve tried for the past two summers to make myself sick of eating tomato sandwiches. I just can&amp;#8217;t.">1</a></sup></p>
<p>Recently, I took the Git survey, and it contained an interesting question along the lines of &#8220;What do you use Git for?&#8221; The answers were things like &#8220;configuration files&#8221; and &#8220;large binary files.&#8221;</p>
<p>I use Git and Github for a lot- configuration files are one use (I love the &#8220;raw&#8221; path), but it was only a small percentage of what that list suggested, so I started wondering how else I could use it.</p>
<p>Today, I thought of an interesting way: Github as a CDN.<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_1_524" id="identifier_1_524" class="footnote-link footnote-identifier-link" title="The title is with Rails because that&amp;#8217;s what I used, but it would take 2.4 minutes to make this a &amp;#8220;With Django&amp;#8221; or &amp;#8220;With Lift&amp;#8221; example">2</a></sup></p>
<p>If you know what a <a href="http://en.wikipedia.org/wiki/Content_delivery_network">Content Delivery Network (CDN)</a> is, you don&#8217;t want me to explain. If you don&#8217;t, then it&#8217;s good enough to say that it&#8217;s a way to server up pictures or other content from another server. It&#8217;s often used to, say, serve the main portion of an html page from a webserver, but serve the images, CSS files, etc. from something like Amazon to speed things up.</p>
<p><img class="alignright" src="http://johnmetta.com/brand/logo.png" alt="" width="300" />I recently finished work on <a href="http://positivelyglorious.com/software-media/john-metta-an-intentional-brand/">The Great John Metta Branding Project</a> and, like with so many projects, stored the images in Dropbox. Then, deciding I might want to version them, I stored them in Github. Then, just as I was starting to begin the rather annoying process of copying all these logos and textmarks to my various sites throughout the web and updating all the image tags, I thought to myself &#8220;Hey, if these are already in Github, and I can access the raw files, why don&#8217;t I just use that as the image source?&#8221; But I don&#8217;t want to have to remember the URL each time. What if it was somewhat dynamically generated?</p>
<h2>A RESTful CDN system for a logo</h2>
<p>This is exactly why I made <a href="http://johnmetta.com">johnmetta.com</a> a Rails project, to play with stuff like this and then have a place to have it be live if I wanted to use it.</p>
<p>I&#8217;ve got a lot of different styles that my logo can take. Stacked, Icon only, textmark only, icon one-color grey, textmark one-color blue, etc. Ideally, I wouldn&#8217;t have to remember the path to each, I could type something like http://johnmetta.com/brand/icon/blue/transparent/logo.png<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_2_524" id="identifier_2_524" class="footnote-link footnote-identifier-link" title="Actually having &amp;#8220;logo.png&amp;#8221; is unnecessary, however, sometimes the software using the URL will depend on that, so I just made it convention so that I don&amp;#8217;t have to think about when sometimes is.">3</a></sup> and have the app return the image that is strictly the icon (no words) with blue coloring and transparency inside the logo (instead of the normal white).</p>
<p>Since none of these actual images is created on the fly, I created a sensible directory structure and embedded all <img class="alignright" src="http://johnmetta.com/brand/icon/logo.png" alt="" width="100" />the files in this structure, naming them all <span style="font-family: courier new,courier">logo.png</span> and putting the default logo in the top level. So the above image would be {base}/full/logo.png, while a version with the icon on top would be {base}/full/stacked/logo.png. A one-color version of only the icon might be {base}/icon/blue/logo.png</p>
<p><img class="alignleft" src="http://johnmetta.com/brand/stacked/blue/logo.png" alt="" width="200" />So I created a <a href="http://github.com/johnmetta/brander">Brander</a> class which would turn arguments into an appropriate path and added some new routes such as &#8220;brand/:type/:color/logo.png&#8221; and created a call to brander in the controller&#8217;s &#8220;brand&#8221; action that ends with a redirect to the returned URL.</p>
<p>It&#8217;s all really simple, but it allows me to have a url like http://johnmetta.com/brand/icon/logo.png and supply my logo, and http://johnmetta.com/brand/stacked/blue/logo.png for a one-color blue stacked logo. Then, if I update the colors (move the files, whatever) they update automatically. At a maximum, I just check in the changes and make minimal changes to the routes- but don&#8217;t have to copy files to servers.</p>
<h2>A Good Illustration</h2>
<p>Right now, the Brander class is pretty dumb- little more than a way to translate a route into the correct external URL. It was built up not as an illustration of how to accomplish &#8220;Github as a CDN,&#8221; but merely as a toy to test one way that it might be done on a small scale. It might be better done as a class where instance attributes make more sense, and I&#8217;ll clean it up a bit, but not much more than that.</p>
<p>Also, it&#8217;s cool to know that stuff like this can be set up so easily, and for my uses- where bandwith might reach a whopping few requests per day, it&#8217;s useful while being low impact. But for a real CDN, you&#8217;d still want to use something like AWS- or at least talk to the Github guys before swamping their webservers.</p>
<ol class="footnotes"><li id="footnote_0_524" class="footnote">I&#8217;ve tried for the past two summers to make myself sick of eating tomato sandwiches. I just can&#8217;t.</li><li id="footnote_1_524" class="footnote">The title is with Rails because that&#8217;s what I used, but it would take 2.4 minutes to make this a &#8220;With Django&#8221; or &#8220;With Lift&#8221; example</li><li id="footnote_2_524" class="footnote">Actually having &#8220;logo.png&#8221; is unnecessary, however, sometimes the software using the URL will depend on that, so I just made it convention so that I don&#8217;t have to think about when sometimes is.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

