<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Taknado: Eugene Bolshakov, Blog</title>
 <link href="http://www.taknado.com/atom.xml" rel="self"/>
 <link href="http://www.taknado.com/"/>
 <updated>2009-10-28T16:11:25+03:00</updated>
 <id>http://www.taknado.com/</id>
 <author>
   <name>Eugene Bolshakov</name>
   <email>eugene.bolshakov@gmail.com</email>
 </author>

 
 <entry>
   <title>Paperclip Tweaks: Convert options, Delete & Rename Attachments, Validate content type and image dimensions</title>
   <link href="http://www.taknado.com/en/2009/10/01/paperclip-tweaks/"/>
   <updated>2009-10-01T00:00:00+04:00</updated>
   <id>http://www.taknado.com/en/2009/10/01/paperclip-tweaks</id>
   <content type="html">&lt;p&gt;I use &lt;a href=&quot;http://github.com/thoughtbot/paperclip&quot;&gt;Paperclip&lt;/a&gt; for attachments in my Rails applications and I find that most of the time I end up using the following tweaks.&lt;/p&gt;
&lt;h3&gt;Convert Options&lt;/h3&gt;
When you define attachments in your model, one of the available parameters is &amp;#8220;convert_options&amp;#8221; which is basically a string of parameters that is passed to image magick when thumbnails are created. I use the following value for the parameter:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;has_attached_file&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:convert_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;-strip -colorspace RGB -resample 72&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The list of supported parameters can be found &lt;a href=&quot;http://www.imagemagick.org/script/command-line-options.php&quot;&gt;here&lt;/a&gt; Below is the description of those that I use.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8220;-strip&amp;#8221; tells IM to strip the image of any profiles or comments, which you probably don&amp;#8217;t need and which helps to reduce the size of the image.&lt;/li&gt;
	&lt;li&gt;&amp;#8220;-colorspace &lt;span class=&quot;caps&quot;&gt;RGB&lt;/span&gt;&amp;#8221; obviously sets the image colorspace to &lt;span class=&quot;caps&quot;&gt;RGB&lt;/span&gt;. It&amp;#8217;s more a specific of projects that I work on, where users sometimes upload &lt;span class=&quot;caps&quot;&gt;CMYK&lt;/span&gt; images that are &lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; not supported by some browsers (like, you know, IE).&lt;/li&gt;
	&lt;li&gt;&amp;#8220;-resample 72&amp;#8221; resamples the image to 72dpi resolution. Again, applications that I work on sometimes get 300dpi images, that need to be converted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use these for all attached images, so it can be DRYed by setting it as a default parameter in say config/initializers/paperclip.rb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Paperclip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Attachment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:convert_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;-strip -colorspace RGB -resample 72&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Delete Attachments&lt;/h3&gt;
&lt;p&gt;Another thing that I need for pretty much any attachment is an ability to delete it (if the attachment is optional). I think a good way to do it is to display the attachment on the &amp;#8220;edit&amp;#8221; page along with a checkbox that if checked removes the attachment. It&amp;#8217;s totally doable, you just need to set the attachment to nil if the box is checked by (I guess) adding some logic to your controller, however it would be nice to have this feature out of the box. And that&amp;#8217;s what I&amp;#8217;ve added to &lt;a href=&quot;http://github.com/eugenebolshakov/paperclip&quot;&gt;my fork of paperclip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Basically it creates a virtual attribute for every attachment in the model that is named like &amp;#8220;image_delete&amp;#8221; if you have an &amp;#8220;image&amp;#8221; attachment. You just need to make sure that it is included in attr_accessible and add a checkbox to your form:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;% if &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;  &amp;lt;%= image_tag form.object.image.url %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%= form.check_box :image_delete, :label =&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Delete Image&amp;#39;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;&amp;lt;% end -%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Rename attachments&lt;/h3&gt;
&lt;p&gt;Paperclip provides a neat way to customize paths to your files using interpolations. It works great if you use things like &amp;#8220;:id&amp;#8221; that never change. However if you&amp;#8217;re really crazy about the URLs of your images and want to have something more meaningful there (e.g. image title &amp;amp; author&amp;#8217;s name like I do in one of my projects) and you update values that interpolations depend on, you need to rename your files as well. Paperclip won&amp;#8217;t do it and hence another feature that is present in &lt;a href=&quot;http://github.com/eugenebolshakov/paperclip&quot;&gt;my fork&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It checks whether it needs to rename files on every update and does it if necessary.&lt;/p&gt;
&lt;h3&gt;Content type and image dimensions validations&lt;/h3&gt;
&lt;p&gt;It&amp;#8217;s a well-known fact that Firefox on Windows does not send correct mime type headers with attachments, that&amp;#8217;s why Paperclip can not correctly validate such uploads. There&amp;#8217;s a &lt;a href=&quot;http://github.com/mattetti/mimetype-fu/&quot;&gt;mimetype-fu plugin&lt;/a&gt; that can figure out the file&amp;#8217;s mime type when it is already in the file system and &lt;a href=&quot;http://github.com/eugenebolshakov/paperclip&quot;&gt;my fork&lt;/a&gt; uses it if it&amp;#8217;s installed.&lt;/p&gt;
&lt;p&gt;Besides it also provides a way to validate image dimensions that is missing out of the box:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;validates_attachment_dimensions&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:minimum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:maximum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;900&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It will check if the image&amp;#8217;s smallest side is bigger than the minimum parameter and the largest side is smaller than the maximum.&lt;/p&gt;
&lt;p&gt;This seems to be it. Paperclip is a great gem and I like it even more with these tiny tweaks.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Cucumber and Unobtrusive Javascript</title>
   <link href="http://www.taknado.com/en/2009/09/25/cucumber-and-unobtrusive-javascript/"/>
   <updated>2009-09-25T00:00:00+04:00</updated>
   <id>http://www.taknado.com/en/2009/09/25/cucumber-and-unobtrusive-javascript</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://blog.solnic.eu/2009/09/08/unobtrusive-javascript-helpers-in-rails-3&quot;&gt;Rails 3&lt;/a&gt; will no longer pollute views with javascript code, which is cool. Until then we&amp;#8217;ve gotta deal with it ourselves. I personally use jQuery and the following simple solution when I need a link that would make an &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; call or a non-&lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; request.&lt;/p&gt;
&lt;p&gt;I add &amp;#8220;method&amp;#8221; and &amp;#8220;method_form&amp;#8221; &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; classes to the links:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;# AJAX&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Delete Item&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Non-GET request (Creates a form and submits it)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Delete Item&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;delete_form&amp;#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And a JS snippet like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;// All A tags with class &amp;#39;get&amp;#39;, &amp;#39;post&amp;#39;, &amp;#39;put&amp;#39; or &amp;#39;delete&amp;#39; will perform an ajax call&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;a.get&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;live&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;href&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;nofollow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;post&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;put&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;a.&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;live&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;auth_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;_method=&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;amp;authenticity_token=&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;auth_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;targetedAjaxSuccess&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;nofollow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// All A tags with class &amp;#39;get_form&amp;#39;, &amp;#39;post_form&amp;#39;, &amp;#39;put_form&amp;#39; or &amp;#39;delete_form&amp;#39; will create a form and submit it&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;get&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;post&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;put&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;a.&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;_form&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;live&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;auth_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;form/&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;get&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;get&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;post&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;input/&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;_method&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;input/&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;authenticity_token&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;auth_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;nofollow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The JS snippet finds all links with the &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; classes and either makes an &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; call or creates a hidden form and submits it when someone clicks on them.&lt;/p&gt;
&lt;p&gt;This works fine, but when it comes to Cucumber and Webrat, they don&amp;#8217;t care about those classes and just make a &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; request when I ask to follow such link. My first solution for fixing it was to modify the default &amp;#8220;When I follow &amp;#8230;&amp;#8221; Cucumber step to find the link first, check if it has a &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; class and use a proper &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; method if it does, like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;When&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /^I follow &amp;quot;([^\&amp;quot;]*)&amp;quot;$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webrat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/(post|put|delete)/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Webrat proxies some methods (like click_link, visit, fill_in, etc) to webrat.current_scope. So that&amp;#8217;s the object you need if you&amp;#8217;d like to call other methods (like find_link in this case). The find_link method returns a Webrat::Link object that in turn has a Nokogiri element object (link.element), so that&amp;#8217;s how you can get its &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; attributes.&lt;/p&gt;
&lt;p&gt;Alright, it works. But wait, Webrat can actually handle inline JS that is generated by default Rails helpers, right? So changing that bit of code to use &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; classes would work for unobtrusive JS as well. And we won&amp;#8217;t have to change the default Cucumber steps every time we update Cucumber. It appears that Webrat does it in Webrat::Link::http_method:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;http_method&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;f.submit()&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;http_method_from_js_form&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If we override this method to look something like this (drop the following to your features/support/env.rb after Webrat is included):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Webrat&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Link&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;css_class&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Webrat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;XML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;http_method_from_css_class&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;sr&quot;&gt;      /(post|put|delete)/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;css_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;http_method&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;http_method_from_css_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The standard Cucumber step starts working like we expect it to, using proper &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; methods for requests.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m pretty sure that something like this will be added to Webrat once Rails 3 is released (cause it won&amp;#8217;t have inline JS anymore). Until then this snippet can be used.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Shoulda Macros in Cucumber Features</title>
   <link href="http://www.taknado.com/en/2009/5/22/shoulda-macros-in-cucumber-features/"/>
   <updated>2009-05-22T00:00:00+04:00</updated>
   <id>http://www.taknado.com/en/2009/5/22/shoulda-macros-in-cucumber-features</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s a well known fact that one can use cucumber with any testing framework. There are a lot of posts on that, but basically one needs to comment out lines that require rspec in features/support/env.rb and update a couple of step definitions that use rspec in features/step_definitions/webrat_steps.rb&lt;/p&gt;
&lt;p&gt;If you use &lt;a href=&quot;http://giantrobots.thoughtbot.com/2009/2/20/mixing-cucumber-with-test-unit&quot;&gt;shoulda&lt;/a&gt; in particular, it also works just fine, however you&amp;#8217;ll notice that you can&amp;#8217;t use controller macros in step definitions. Although this is correct in terms of ideology (you should be using them in functional tests instead) and technology (&lt;a href=&quot;http://github.com/thoughtbot/shoulda/blob/7d6aa5b6ecceef0bef3399bc328275a3700e06ac/lib/shoulda/action_controller.rb&quot;&gt;macros are not included in ActionController::Integration::Session&lt;/a&gt; which is the context of cucumber step definitions) depending on the way you use Cucumber and write your features, you may want to use them.&lt;/p&gt;
&lt;p&gt;First, you&amp;#8217;ve got to mix Cucumber and shoulda matchers by adding this line to features/support/env.rb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Shoulda&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Matchers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It will make matchers accessible in your step definitions. At this point, if you were using Rspec you could relax, cause the following step definition would work perfectly:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Then&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /^the &amp;quot;(.*)&amp;quot; layout should be used$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_with_layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;But since you&amp;#8217;re a shoulda addict, read on.&lt;/p&gt;
&lt;p&gt;Shoulda macros are supposed to be class methods of Test::Unit::TestCase and they obviously won&amp;#8217;t work as instance methods of ActionController::Integration::Session. But if you take a peek at the &lt;a href=&quot;http://github.com/thoughtbot/shoulda/blob/7d6aa5b6ecceef0bef3399bc328275a3700e06ac/lib/shoulda/action_controller/macros.rb&quot;&gt;sources of standard macros&lt;/a&gt;, you&amp;#8217;ll notice that they use matchers (which makes sense to avoid duplication) internally.&lt;/p&gt;
&lt;p&gt;Besides matchers and macros shoulda adds a bunch of assertions to your tests. One of them is assert_accepts, that takes a matcher and an object that&amp;#8217;s being tested and asserts that the object meets the matcher requirements. Exactly this assertion is used in the standard shoulda macros and you can use it as well in your step definitions:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Then&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /^the &amp;quot;(.*)&amp;quot; layout should be used$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assert_accepts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_with_layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And that&amp;#8217;s it. You&amp;#8217;ve got access to shoulda matchers in your cucumber step definitions without rspec, which is basically the same as using macros.&lt;/p&gt;
&lt;p&gt;Now one could argue that you should not test which layout is rendered in your acceptance tests. And personally I don&amp;#8217;t. But as I mentioned above, it depends on the way you use cucumber. It&amp;#8217;s just a tool and there many ways it could be used. I would say that if it makes you productive and your software more robust and maintainable, you&amp;#8217;re doing it right.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Ruby Group Meeting in SPB. Как это было и зачем</title>
   <link href="http://www.taknado.com/ru/2009/5/5/ruby-group-meeting-in-spb/"/>
   <updated>2009-05-05T00:00:00+04:00</updated>
   <id>http://www.taknado.com/ru/2009/5/5/ruby-group-meeting-in-spb</id>
   <content type="html">&lt;p&gt;26 апреля в Питере в &lt;a href=&quot;http://www.iclub.su&quot;&gt;iClub&lt;/a&gt; прошло собрание любителей Ruby. Это было второе мероприятие в рамках railsclub.ru, поэтому информация о нем и материалы есть на &lt;a href=&quot;http://www.railsclub.ru&quot;&gt;официальном сайте&lt;/a&gt;. Для меня это был первый опыт орагнизации встречи и публичного выступления. Было довольно интересно и я надеюсь мы будем собираться регулярно. Меня несколько раз спрашивали о том, зачем вообще нужны эти встречи, кто может в них участвовать и т.д. Я хочу поделиться своими мыслями на этот счет с надеждой привлечь больше людей на будующие встречи, а так же сделать их лучше.&lt;/p&gt;
&lt;h2&gt;О чем рассказать на такой встрече&lt;/h2&gt;
&lt;p&gt;Все, чем Вы занимаетесь, что более-менее необычно, может быть интересно другим.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;У Вас есть какая-то open source (или которой можно поделиться) наработка для решения какой-то задачи.&lt;/li&gt;
	&lt;li&gt;Есть проект, над которым Вы работаете и решили какие-то проблемы определенным образом (организация кода, процесса, производительность&amp;#8230;).&lt;/li&gt;
	&lt;li&gt;Вы Начали использовать какой-то новый подход или инструмент и он Вам нравится.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Стоит только спросить — интересно ли это кому-то и почти наверняка найдутся интересующиеся.&lt;/p&gt;
&lt;h2&gt;Зачем выступать&lt;/h2&gt;
&lt;h3&gt;Цели, которые можно достичь напрямую&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;Привлечь разработчиков к своему open source проекту&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Чтобы их привлечь нужно показать, что проект полезный и интересный. Выступление с демонстрацией основных фишек — отличный способ это сделать.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Заинтересовать (напрямую или косвенно) своим коммерческим продуктом&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Продукт может быть любым — как непосредственно для аудитории, так и для всех. Можно рассказать о продукте, который Вы разрабатываете, об особенностях, технических задачах, которые пришлось решить и тем самым привлечь внимание. Либо косвенно упомянуть о продукте в контексте выступления.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Найти работников или работу&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Невозможно получить полное представление о потенциальной работе по объявлению, одному разговору с менеджером по персоналу, директором и т.д. Так же невозможно понять подходит ли потенциальный работник, задав несколько шаблонных вопросов (почему Вы хотите работать в нашей компании? — Я понятия не имею — разослал резюме в миллиард мест) и получив на них такие же шаблонные ответы. Есть возможность узнать больше о компании или работнику по блогу, open source проектам и т.д. Но я думаю общение в неформальной и не связанной с рекрутингом обстановке может сказать даже больше. Выступление для компании — возможность рассказать о себе перед целевой аудиторией в контексте какого-то проекта например. Для разработчика — возможность выступить перед потенциальными работодателями или коллегами.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Найти &lt;a href=&quot;http://tom.preston-werner.com/2008/11/03/how-to-meet-your-next-cofounder.html&quot;&gt;единомышленников&lt;/a&gt; для работы над проектом&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;На одном из подобных собраний &lt;a href=&quot;http://tom.preston-werner.com/2008/10/18/how-i-turned-down-300k.html&quot;&gt;появился github&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Сформировать бренд или реализовать амбиции (В хорошем смысле, если он вообще есть)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jay Fields об этом &lt;a href=&quot;http://blog.jayfields.com/2008/08/be-your-start-up.html&quot;&gt;написал&lt;/a&gt; явно лучше меня.&lt;/p&gt;
&lt;h3&gt;Цели, которые можно решить косвенно&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;Хорошо изучить предмет, о котором Вы будете рассказывать&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Я узнал довольно много о cucumber и связанных вещах, когда готовился к выступлению.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;По-новому посмотреть на инструмент (процесс, решение, и т.д.), который Вы используете&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Раза 2 я поменял свое отношение к тому, как я пишу cucumber features. В какой-то момент задумался о том, нужно ли мне их вообще писать. Это произошло, потому что я попытался найти как можно больше материалов по теме от разных людей.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Взглянуть на продукт (библиотеку, и т.д.) со стороны человека, который о нем ничего не знает&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Это очень полезно, когда Вы рассказываете о чем-то своем. Разработчику очень тяжело отвлечься и посмотреть на результат своей деятельности глазами пользователя. А это невероятно важно.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Научиться доступно излагать свои мысли и выступать публично&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Думаю это полезно всем и каждому.&lt;/p&gt;
&lt;h3&gt;Глобальные цели&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;Привлечение новых людей в сообщество&lt;/li&gt;
	&lt;li&gt;Обучение начинающих&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Новые люди — новые взгляды и новые проекты.&lt;/p&gt;
&lt;h3&gt;Зачем это мне?&lt;/h3&gt;
&lt;p&gt;Для меня это интересный опыт, возможность пообщаться (я работаю дома один) и удовлетворение от безкорыстно совершенного поступка.&lt;/p&gt;
&lt;h2&gt;Зачем приходить&lt;/h2&gt;
&lt;p&gt;Многое можно найти в Интернете и прочитать (и многие так и делают, когда перед ними встает проблема или задача). Зачем тогда приходить?&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Организованное обучение (Не нужно искать, выбирать время, настраиваться и т.д.)&lt;/li&gt;
	&lt;li&gt;Можно влиять на процесс изложения (в своих интересах) — задавать вопросы&lt;/li&gt;
	&lt;li&gt;Встретить людей, решающих те же проблемы что и Вы&lt;/li&gt;
	&lt;li&gt;Пообщаться и интересно провести время&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Как рассказывать&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;Коротко. На следующей встрече мы постараемся ограничится 15-20 минутами на выступление&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Мои 40 минут были явно перебором.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Конкретная и специфическая тема лучше чем общая и пространная&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Я набрал себе кучу тем и в итоге только поверхностно по ним прошелся. Лучше полноценно рассказать о чем-то небольшом.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Хорошо показывать на конкретном реальном примере&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Маленькое конкретное приложение лучше, чем словесное описание абстрактной проблемы.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Кодинг в живую — это вероятно лучший способ, но это нужно уметь делать&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Я думаю все видели хорошие и плохие скринкасты. В плохих автор неуклюже мечется туда-сюда, опечатывается, а потом пытается разобраться почему ничего не работает. Это отвлекает от темы. Я не умею писать код в живую, поэтому написал весь код заранее.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Лучше подготовить все заранее, чтобы не тупить во время выступления&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;На выступлении я по сути первый раз пользовался маком. Как сделать шрифт крупнее? Куда ставятся gems? На эти вопросы не должны отвечать те, кто пришел послушать мое выступление.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Код должен быть хорошо виден&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Иначе смысла нет его показывать. Настраивайте размер шрифта заранее.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>SSH without password</title>
   <link href="http://www.taknado.com/en/2009/3/30/ssh-without-password/"/>
   <updated>2009-03-30T00:00:00+04:00</updated>
   <id>http://www.taknado.com/en/2009/3/30/ssh-without-password</id>
   <content type="html">&lt;p&gt;I don&amp;#8217;t mean to break new ground here, but for one or another reason it took me a while a couple of times to figure out why it didn&amp;#8217;t work. There&amp;#8217;s a huge amount of posts out there that describe how to setup SSHing to your server without a password, which have different sets of steps to make it work. This one seems to work for me (figured by trial and error):&lt;/p&gt;
&lt;p&gt;On your server you need to make sure that ~/.ssh dir exists. Then make sure that the permissions are correct:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;chmod go-w ~/
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;chmod 700 ~/.ssh
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;chmod 600 ~/.ssh/authorized_keys
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you need to generate an &lt;span class=&quot;caps&quot;&gt;RSA&lt;/span&gt; key unless you already have it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;/home/user/.ssh/id_rsa&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: 
Enter passphrase &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;empty &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;no passphrase&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;So now you have the key generated in ~/.ssh/id_rsa, and the filnal step is to copy the generated key to the server. I use Ubuntu and do it this way:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;ssh-copy-id -i ~/.ssh/id_rsa.pub username@host
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;At this point you should be all set. Try to ssh to the server and it won&amp;#8217;t prompt for a password.&lt;/p&gt;
&lt;p&gt;Update: There&amp;#8217;s a really neat feature (&lt;a href=&quot;http://giantrobots.thoughtbot.com/2009/3/30/2009-rubyist-guide-mac-os-x-development-environment&quot;&gt;thanks, Dan&lt;/a&gt;) that let&amp;#8217;s you create ssh aliases, so you could do &amp;#8220;ssh production&amp;#8221; instead of &amp;#8220;ssh user@production.host.com&amp;#8221;. Aliases can be specified in ~/.ssh/config like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cat /home/eugene/.ssh/config 
Host production
HostName production.host.com
User user

Host staging
HostName staging.host.com
User user
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This is a nice addition to the ablility to ssh without passwords.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Deploying a jekyll generated site</title>
   <link href="http://www.taknado.com/en/2009/03/26/deploying-a-jekyll-generated-site/"/>
   <updated>2009-03-26T00:00:00+03:00</updated>
   <id>http://www.taknado.com/en/2009/03/26/deploying-a-jekyll-generated-site</id>
   <content type="html">&lt;p&gt;Ok, so I&amp;#8217;ve finally migrated this blog from mephisto to &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;jekyll&lt;/a&gt; and just want to share a couple of gotchas.&lt;/p&gt;
&lt;p&gt;The migration itself went pretty well. I&amp;#8217;ve used scripts posted &lt;a href=&quot;http://blog.new-bamboo.co.uk/2009/2/20/migrating-from-mephisto-to-jekyll&quot;&gt;here&lt;/a&gt; to dump posts (although then I noticed that there&amp;#8217;s a mephisto converter in jekyll itself that is not mentioned in the &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;) and move comments to &lt;a href=&quot;http://disqus.com/&quot;&gt;disqus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;There was one thing with URLs though. I&amp;#8217;m using &amp;#8220;pretty&amp;#8221; permalink style which generates directories for each post and puts an index.html with the post itself there (like /2009/3/26/deploying-a-jekyll-generated-site/index.html) so you could have URLs without &amp;#8220;.html&amp;#8221; at the end (/2009/3/26/deploying-a-jekyll-generated-site/), cause I had this type of URLs in mephisto. Now apache redirects you to &amp;#8220;/url/&amp;#8221; if you type &amp;#8220;/url&amp;#8221; in this case. And for disqus &amp;#8220;/url&amp;#8221; and &amp;#8220;/url/&amp;#8221; are two different URLs and if you dumped comments with URLs without the trailing slash, they won&amp;#8217;t be displayed.&lt;/del&gt; &lt;strong&gt;This issue with pretty URLs is now fixed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then another thing was how to deploy the site. I&amp;#8217;m hosting this on a shared dreamhost account and thus it would be difficult to generate the site on the server. It doesn&amp;#8217;t have pygments (which is used for syntax highlighting) and I was using the edge version of jekyll.&lt;/p&gt;
&lt;p&gt;So I added the generated site (&amp;#8220;_site&amp;#8221; dir) to the git repo, created a clone of the repo on dreamhost, pointed the domain to the &amp;#8220;_site&amp;#8221; dir and added a post-update hook to the remote repo (hosted on the same account) which does &amp;#8220;git pull&amp;#8221; on dreamhost after every &amp;#8220;git push&amp;#8221; on my end:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cat ~/git/blog.git/hooks/post-update 
&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;unset &lt;/span&gt;GIT_DIR &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /home/eugenebolshakov/blog/ &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The important thing here is &amp;#8220;unset GIT_DIR&amp;#8221;. post-update is called by receive-pack that sets GIT_DIR to &amp;#8216;.&amp;#8217; and confuses &amp;#8220;git pull&amp;#8221;. I&amp;#8217;ve found the hint &lt;a href=&quot;http://www.mail-archive.com/git@vger.kernel.org/msg03458.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now I can just add a post, generate the site ( &lt;del&gt;I have a shortcut script for that in the repo with the params I use&lt;/del&gt; &lt;strong&gt;_config.yml works great for that&lt;/strong&gt;), do git push and I&amp;#8217;m all set. Nice!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Hoptoad as an online application events log</title>
   <link href="http://www.taknado.com/2008/10/19/hoptoad-as-an-online-events-log/"/>
   <updated>2008-10-19T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2008/10/19/hoptoad-as-an-online-events-log</id>
   <content type="html">&lt;p&gt;Now everyone&amp;#8217;s familiar with &lt;a href=&quot;http://hoptoadapp.com/&quot;&gt;Hoptoad&lt;/a&gt;, right? It&amp;#8217;s &amp;#8220;cool&amp;#8221;, &amp;#8220;slick&amp;#8221;, &amp;#8220;essential&amp;#8221; and is &amp;#8220;your friend&amp;#8221; when it comes to collecting and analyzing errors in your Rails application.&lt;/p&gt;
&lt;p&gt;&amp;#8220;When an uncaught exception occurs, HoptoadNotifier will &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; the relevant data  to the Hoptoad server specified in your environment.&amp;#8221; But besides that it can also store any kind of information you want. That&amp;#8217;s what the documentation says:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#If you want to log arbitrary things which you&amp;#39;ve rescued yourself from a&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#controller, you can do something like this:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;5&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;notify_hoptoad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;6&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:failure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Encryptions could not be rerouted, try again.&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What it does not say (but the comments in the sources do) is that you can also pass a hash to notify_hoptoad method and store whatever you want, not just an exception. And you can also use it anywhere, not just in controllers.&lt;/p&gt;
&lt;p&gt;Now let&amp;#8217;s assume you have an online store that uses some sort of third party &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; to calculate shipping costs. That &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; like any other thing you have no control over can unpredictably go down from time to time. In that case you don&amp;#8217;t want to display an error page, but instead use some predefined shipping rate and let the customer complete his purchase. But still you want to be aware of that say to analyze how stable the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; is and maybe start looking for something else if it goes down too often.&lt;/p&gt;
&lt;p&gt;So inside your code where you make a call to the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; you can notify Hoptoad when it goes down like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;lineno&quot;&gt; 1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_quantity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:weight&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:postcode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;postcode&lt;/span&gt;    
&lt;span class=&quot;lineno&quot;&gt; 7&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shipping_rates&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ShippingCalculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shipping_rates&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt; 9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10&lt;/span&gt;   &lt;span class=&quot;no&quot;&gt;HoptoadNotifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:error_class&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Shipping Calculator Error&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:error_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Shipping Calculator Error: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:request&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shipping_rates&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_shipping_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;While in your controllers you can use the &amp;#8220;notify_hoptoad&amp;#8221; method which is mixed in when the plugin is loaded, anywhere else in your code HoptoadNotifier.notify  can be used that like the &amp;#8220;notify_hoptoad&amp;#8221; accepts either an exception or a hash. It&amp;#8217;s all clear with an exception &amp;#8211; Hoptoad will get all the information about the error itself. As for a hash, this are the keys you should pass:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;:error_class &amp;#8211; Use this to group similar errors together. Apparently when Hoptoad catches an exception it sends the class name of that exception object.&lt;/li&gt;
	&lt;li&gt;:error_message &amp;#8211; This is the title of the error you see in the errors list. For exceptions it is &amp;#8220;#{exception.class.name}: #{exception.message}&amp;#8221;&lt;/li&gt;
	&lt;li&gt;:request &amp;#8211; While there are several ways to send additional data to Hoptoad, I&amp;#8217;ve found passing a Hash with :params key as :request suitable for the situation described above. Apparently when Hoptoad catches an exception in a controller the actual &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; client request is being sent using this key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hoptoad merges the hash you pass with these default options:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;lineno&quot;&gt; 1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default_notice_options&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#:nodoc:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:api_key&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HoptoadNotifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:error_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Notification&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:backtrace&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:request&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:session&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_hash&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As you can see there are several other parameters you can set / override.&lt;/p&gt;
&lt;p&gt;So at the end of the day I have a store that allows people to buy stuff no matter what happens to the Shipping &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; I use and at the same time I keep track of problems that occur in the background using a nice and friendly web interface&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Poking in ActionController</title>
   <link href="http://www.taknado.com/2007/10/30/poking-in-actioncontroller/"/>
   <updated>2007-10-30T00:00:00+03:00</updated>
   <id>http://www.taknado.com/2007/10/30/poking-in-actioncontroller</id>
   <content type="html">&lt;p&gt;I have an &amp;#8216;accept&amp;#8217; action in one of the controllers and when I was trying to run a functional test against it I got:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;ActionController::UnknownAction in &lt;span class=&quot;s1&quot;&gt;&amp;#39;ContributorRequestsController for moderator allow to accept a request&amp;#39;&lt;/span&gt;
No action responded to accept
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And of course it worked fine when I&amp;#8217;ve actually started the server and invoked it from browser.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve realized that the reason probably was some name clashing or something, but it only appeared in the tests. So I&amp;#8217;ve decided to have some debugging fun and I think the outcome is the case when code extracts speak louder than words:&lt;/p&gt;
&lt;p&gt;ActionController::Base:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;perform_action&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action_methods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UnknownAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;No action responded to &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;action_methods&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@action_methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;public_instance_methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hidden_actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hidden_actions&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;write_inheritable_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hidden_actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;public_instance_methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read_inheritable_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hidden_actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;read_inheritable_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hidden_actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If your action is named as one of the ActionController::Base.public_instance_methods then it won&amp;#8217;t be invoked. While that&amp;#8217;s reasonable, I wondered what that reserved &amp;#8216;accept&amp;#8217;  method did. I&amp;#8217;ve failed to find it in the rails and rspec sources and finally simply did a search for &amp;#8216;def accept&amp;#8217; against the project and found it in lib/authenticated_test_helper.rb which is generated by acts_as_authenticated plugin.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;HTTP_ACCEPT&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accept&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>NetBeans + BEA JRockit</title>
   <link href="http://www.taknado.com/2007/10/1/netbeans-bea-jrockit/"/>
   <updated>2007-10-01T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/10/1/netbeans-bea-jrockit</id>
   <content type="html">&lt;p&gt;NetBeans Ryby &lt;span class=&quot;caps&quot;&gt;IDE&lt;/span&gt; was cool. On my PC at work. But when I&amp;#8217;ve got a new laptop and switched to working on it, it appeared to be dead slow when editing &lt;span class=&quot;caps&quot;&gt;RHTML&lt;/span&gt; files. I&amp;#8217;ve tried to figure out the reason (tried different builds, settings, etc&amp;#8230;) and finally realized that I&amp;#8217;ve had &lt;a href=&quot;http://www.bea.com/framework.jsp?CNT=index.htm&amp;amp;FP=/content/products/weblogic/jrockit/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;BEA&lt;/span&gt; JRockit &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt;&lt;/a&gt; on my PC and &lt;span class=&quot;caps&quot;&gt;SUN&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;JVM&lt;/span&gt; on the laptop. So I&amp;#8217;ve installed &lt;a href=&quot;http://www.bea.com/framework.jsp?CNT=index.htm&amp;amp;FP=/content/products/weblogic/jrockit/&quot;&gt;JRockit&lt;/a&gt; and now it seems to work great again.&lt;/p&gt;
&lt;p&gt;So the moral is that NetBeans appears to work faster on AMD64x2/Ubuntu laptop with &lt;a href=&quot;http://www.bea.com/framework.jsp?CNT=index.htm&amp;amp;FP=/content/products/weblogic/jrockit/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;BEA&lt;/span&gt; JRockit&lt;/a&gt;. Perhaps not just for me&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Перевод серии статей про REST on Rails</title>
   <link href="http://www.taknado.com/2007/8/31/rest-on-rails/"/>
   <updated>2007-08-31T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/8/31/rest-on-rails</id>
   <content type="html">&lt;p&gt;Когда я искал инфу о &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;, то нашел на мой взгляд хороший &lt;a href=&quot;http://www.softiesonrails.com/tags/rest&quot;&gt;туториал (101) из 5-ти частей&lt;/a&gt;, автором которого является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;. Сам автор предложил опубликовать ссылки на переводы туториала на другие языки и я решил попробовать перевести его на русский. Я далеко не переводчик, и не филолог/лингвист, поэтому перевод наверняка изобилует разнообразными ошибками. Если есть желание принять участие в редактировании &amp;#8211; пишите. И конечно, всегда лучше читать подобные вещи в оригинале (там  с картинками и прибаутками), но тем не менее вот:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;/2007/7/30/rest-1&quot;&gt;Часть 1. Ресурсы.&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/2007/7/31/rest-2&quot;&gt;Часть 2. Миллионы &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/2007/8/1/rest-3&quot;&gt;Часть 3. Проектирование согласно &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;.&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/2007/8/8/rest-4&quot;&gt;Часть 4. Маршрутизация.&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/2007/8/31/rest-5&quot;&gt;Часть 5. Ответ.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;P.S. Большое спасибо Антону (aka Tonic) за помощь с переводом.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>REST Ликбез. Часть 5. Ответ.</title>
   <link href="http://www.taknado.com/2007/8/31/rest-5/"/>
   <updated>2007-08-31T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/8/31/rest-5</id>
   <content type="html">&lt;p&gt;Перевод (подробности &lt;a href=&quot;/2007/8/31/rest-on-rails&quot;&gt;здесь&lt;/a&gt;) статьи &lt;a href=&quot;http://www.softiesonrails.com/2007/5/1/rest-101-part-5-respond&quot;&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; 101: Part 5 &amp;#8211; Respond!&lt;/a&gt;, автором которой является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;В предыдущей статье мы узнали, как Rails позволяет обращаться к ресурсам средствами &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;. Но наше приложение будет использоваться не только с помощью обычных &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; браузеров, но и с сотовых телефонов, а так же другими приложениями через &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;С 1-ой по 4-ую статьи мы знакомились с основами концепции &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; и к текущему моменту все точки расставлены. Осталось соединить их линиями, чтобы увидеть картину целиком. Это моя любимая часть, в том числе потому, что в ней рассмотрена реализация &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; в Rails, являющаяся еще одним примером того, насколько прекрасен Ruby.&lt;/p&gt;
&lt;p&gt;Коротко, но так&amp;#8230; мило&lt;/p&gt;
&lt;p&gt;Для того чтобы наше &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; приложение заработало, нужно заставить контроллер правильно отвечать на запросы в зависимости от того, кто находится на другом конце провода и отправляет их. В качестве простого примера можно рассмотреть получение списка аэропортов. Если Вы воспользовались генератором scaffold_resource, то у Вас должен был получиться примерно такой код:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AirportsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@airports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Airport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;respond_to&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# do nothing, allow Rails to render index.rhtml&lt;/span&gt;
                &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;js&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# do nothing, allow Rails to render index.rjs&lt;/span&gt;
                &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@airports&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Первая строка метода понятна &amp;#8211; получаем все аэропорты. Но остальной код выглядит несколько необычно. Все что он делает &amp;#8211; это отображает список аэропортов в &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; и даже с использованием &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt;, если это потребуется. Для того, чтобы понять, как это работает нужно познакомиться с respond_to.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; клиенты могут добавить различную мета-информацию к своему запросу в виде &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; заголовков. Заголовок &amp;#8211; это просто необязательная пара ключ-значение. Существует несколько определенных стандартом заголовков, которые могут быть использованы. например заголовок &amp;#8220;Accept-Type&amp;#8221;. В качестве значения этого заголовка клиент может передать формат, в котором он способен прочитать ответ. В качестве значения может выступать любой из &lt;span class=&quot;caps&quot;&gt;MIME&lt;/span&gt; types, но если значение этого заголовка не указано, то сервер считает что клиент способен адекватно воспринять &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;. Таким образом, если клиент посылает заголовок &amp;#8220;Accept-Type: text/xml&amp;#8221;, то предполагается что сервер вернет ответ в виде &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; документа.&lt;/p&gt;
&lt;p&gt;Именно заголовок Accept-Type вызывает магические действия внутри блока resond_to. Вот плохой пример того, как можно было бы реализовать поддержку различных форматов (предположим что Rails передает значение заголовка Accept-Type в наш метод):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AirportsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Pretend that Rails will call our index action, &lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# and will pass in the value of the Accept-Type header&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@airports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Airport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# TO DO: render the default template&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;application/javascript&amp;quot;&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# TO DO: return some javascript&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;application/xml&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;text/xml&amp;quot;&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# TO DO: return some XML back the client&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;# ... more elsif statements here for each MIME type you want to support&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Но это некрасиво&lt;/p&gt;
&lt;p&gt;Если закрыть глаза на уродство, то будет видно что сам по себе алгоритм очень прост &amp;#8211; в зависимости от запрашиваемого формата отображаем список аэропортов тем или иным образом. Я легко могу себе представить, как команда разработчиков Rails стартовала с подобного кода (хотя бы в голове), но быстро решила просто добавить хэлпер respond_to, чтобы избежать безобразия:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt; respond_to &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; |format|
    format.html  &lt;span class=&quot;c&quot;&gt;# do nothing, allow Rails to render index.rhtml&lt;/span&gt;
    format.js    &lt;span class=&quot;c&quot;&gt;# do nothing, allow Rails to render index.rjs&lt;/span&gt;
    format.xml   &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; render :xml &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; @airports.to_xml &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  end
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Мы можем не знать, как устроен метод respond_to, но мы точно знаем, что он принимает Ruby блок. (Если Вы не знакомы с блоками в Ruby, попробуйте немного погуглить и возвращайтесь обратно). Внутри блока Вы получаете в свое распоряжение объект, который я назвал format и вызываете три метода этого объекта.&lt;/p&gt;
&lt;p&gt;Идея состоит в том, что Rails не может догадаться, какие типы клиентов Вы хотите поддерживать, но может сделать 80% черной работы за Вас. Необходимо только указать типы клиентов, которые Вас интересуют, и отобразить ресурс в виде, понятном клиенту. Вместо того, чтобы говорить Вам какой формат ответа запрашивается, Rails просит Вас указать, какие форматы Вы готовы поддерживать. И для каждого формата (если захотите) можно указать блок кода, который непосредственно отобразит ресурс.&lt;/p&gt;
&lt;p&gt;В приведенном выше примере мы говорим Rails, что для клиентов, запрашивающих &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; и Javascript можно выполнить действие по умолчанию &amp;#8211; отобразить шаблон в соответствующем формате, но если клиент хочет получить &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;, необходимо выполнить указанный нами блок кода.&lt;/p&gt;
&lt;p&gt;Помните, как когда-то очень давно мы говорили о разнице между ресурсом и множеством различных его представлений? О том, что &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; &amp;#8211; это на самом деле всего лишь одно из возможных представлений (Ваше приложение это не &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; страница и т.д.)? Теперь это видно даже в коде &amp;#8211; &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; всего лишь один из вариантов.&lt;/p&gt;
&lt;p&gt;Что дальше?&lt;/p&gt;
&lt;p&gt;Понятно, что невозможно охватить все, что связано с &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; в нескольких статьях. Именно поэтому серия и называется &amp;#8220;ликбез&amp;#8221;. Но мы поговорили о многом, в том числе и о том, как проектировать приложения согласно &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;, о концепции ресурсов и о том, как это отличается от традиционного ООП подхода.&lt;/p&gt;
&lt;p&gt;Думаете о том, что же делать дальше? Просто попробуйте! Создайте &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; приложение с нуля, воспользуйтесь генератором scaffold_resource, изучите сгенерированный код, попробуйте подредактировать views и контроллеры. Это легче чем Вы думаете.&lt;/p&gt;
&lt;p&gt;Вот некотрые источники, которые я могу порекомендовать для более подробного изучения (обратите внимание, PeepCode поддерживает блог автора)&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/restful-rails&quot;&gt;PeepCode скринкаст о &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.scribemedia.org/2006/07/09/dhh/&quot;&gt;Выступление DHH&amp;#8217;s на RailsConf 2006&lt;/a&gt; и &lt;a href=&quot;http://www.loudthinking.com/arc/000593.html&quot;&gt;запись в его блоге&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Держите руку на пульсе Edge Rails вместе с &lt;a href=&quot;http://ryandaigle.com/&quot;&gt;Ryan Daigle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Можете посоветовать что-то еще? Оставляйте ссылки в комментариях.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails + Windows Command Line Tips</title>
   <link href="http://www.taknado.com/2007/8/16/rails-windows-commans-line-tips/"/>
   <updated>2007-08-16T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/8/16/rails-windows-command-line-tips</id>
   <content type="html">&lt;p&gt;We do lot&amp;#8217;s of things from console when using Rails and it can be a little painful on Windows. However, we can try to make our lives better.&lt;/p&gt;
&lt;p&gt;To begin with, I must confess in being a great lamer. I always used Windows (Update: Finally on Ubuntu!) (except some crazy attempts including a night session of trying to run MacOSx86 on VmWare, qemu and kqemu under Linux on a processor that doesn&amp;#8217;t support SSE2), never used things like Far manager (the tool used by all crazy Windows guys, well, at least in Russia), never wrote bat files (except the ones in the University that were considered to be viruses by &lt;a href=&quot;http://www.kaspersky.com/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;AVP&lt;/span&gt;&lt;/a&gt; for some reason), never managed to remember all those tricky keyboard shortcuts, nothing.&lt;/p&gt;
&lt;p&gt;But once started to use Rails I began to love The Console. Really, lot&amp;#8217;s of things can be done easier and faster. But there are several things I don&amp;#8217;t like about the Windows console (cmd.exe).&lt;/p&gt;
&lt;p&gt;First of all, I use gems documentation a lot. The one that can be accessed from the browser on the 8808 port (by default) when you run gem_server. It&amp;#8217;s cool. The only thing I hated about it is that I had to run it every day and that its console window was hanging about the desktop. So I&amp;#8217;ve found a nice tool called &lt;a href=&quot;http://www.ntwind.com/software/utilities/hstart.html&quot;&gt;Hidden Start&lt;/a&gt; that allows to run console applications in the background without any windows. So I&amp;#8217;ve simply added it to the Startup folder and now I can access RDoc gems documentation instantly!&lt;/p&gt;
&lt;p&gt;The next thing I do very often is starting the console session to run tests, rake tasks or other things against my Rails application. The thing I hated is that I had to change the current directory (home directory that is opened by default when one starts cmd.exe) to the directory of the application, which always took a while cause I&amp;#8217;ve had to change the drive and type the long path to the application. I wanted just to open a console and type a command without changing the directory. It appeared that one can change the default cmd directory by hacking the registry, but I didn&amp;#8217;t want that cause I have several applications that I want to use console with. So I created a shortcut for cmd that opens the console window and sets the current directory (I&amp;#8217;ve found the parameters somewhere on the net):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;%windir%&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;ystem32&lt;span class=&quot;se&quot;&gt;\c&lt;/span&gt;md.exe /k &lt;span class=&quot;s2&quot;&gt;&amp;quot;cd /d d:\really_long_path_to_my_rails_project&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The last thing is the Rails Application Server. I currently use Mongrel, but it doesn&amp;#8217;t really matter. Every day I had to open the console window, change the directory (Shit! Again!) and run ruby script/console, which I also hated of course. This time a simple bat file saved my hair (at least for a while):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /d d:/really_long_path_to_my_rails_project
ruby script/server
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I&amp;#8217;ve added the above mentioned 2 files to my quick launch panel and now I feel happier! But as stated, I&amp;#8217;m a lamer, so I&amp;#8217;ll be grateful to hear ideas on how to make it better.&lt;/p&gt;
&lt;p&gt;Update: In love with Ubuntu for more than a year now&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>REST Ликбез. Часть 4. Маршрутизация.</title>
   <link href="http://www.taknado.com/2007/8/8/rest-4/"/>
   <updated>2007-08-08T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/8/8/rest-4</id>
   <content type="html">&lt;p&gt;Перевод (подробности &lt;a href=&quot;/2007/8/31/rest-on-rails&quot;&gt;здесь&lt;/a&gt;) статьи &lt;a href=&quot;http://www.softiesonrails.com/2007/4/18/rest-101-part-4-routing&quot;&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; 101: Part 4 &amp;#8211; Routing&lt;/a&gt;, автором которой является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ранее мы выяснили, что проектирование системы согласно &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; начинается с выявления ключевых ресурсов. Сегодня нам предстоит узнать, как Rails обрабатывает &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; запросы, и каким образом Ваш код должен на них реагировать.&lt;/p&gt;
&lt;p&gt;Я также хочу немного отойти в сторону и напомнить, что &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; &amp;#8211; это технология, применяемая не только в Rails. &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; изобрели гораздо раньше, и это подход, который можно использовать при разработке различных программ вне зависимости от используемых инструментов. Теперь, когда я знаком с &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;, я скорее всего не буду писать WinForms приложения так, как я делал это раньше.&lt;/p&gt;
&lt;p&gt;Ресурс == Контроллер&lt;/p&gt;
&lt;p&gt;Вы уже знакомы с моделями и контроллерами. Но как реализовать &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; приложение с их помощью? В первую очередь нужно усвоить несколько вещей:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Ресурс не всегда соответствует модели Rails или таблице в базе данных. Иногда ресурс является &amp;#8220;виртуальным&amp;#8221; и существует только в описании бизнес модели и логике приложения, но не связан с таблицей в базе.&lt;/li&gt;
	&lt;li&gt;Тем не менее ресурс всегда связан с контроллером.&lt;/li&gt;
	&lt;li&gt;Любители (такие как я) абстрактных интерфейсов могут считать класс-контроллер реализацией интерфейса &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;Контроллер реализует ресурс вне зависимости от того, какой клиент к нему обращается (&lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; браузер, &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; клиент, &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; парсер, и т.д.), и таким образом, ему необходимо отправлять ответ в том формате, в котром его ожидает клиент. В 3-ей части я описывал, что нам необходимо реализовать поддержку нескольких типов клиентов (&lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;, мобильный телефон, &lt;span class=&quot;caps&quot;&gt;RICH&lt;/span&gt; клиент и т.д.) для одних и тех же ресурсов. Один контроллер реализует отображение данных ресурса независимо от формата запроса.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Семь&lt;/p&gt;
&lt;p&gt;Большинство ресурсов запрашиваются индивидуально (аэропорт), либо в виде коллекции (список аэропортов). Ваш контроллер будет реализовывать следующие семь действий (методов).&lt;/p&gt;
&lt;p&gt;Четыре этих:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;show : обрабатывает &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; запрос для отображения индивидуального ресурса&lt;/li&gt;
	&lt;li&gt;create : обрабатывает &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; запрос для создания нового экземпляра ресурса&lt;/li&gt;
	&lt;li&gt;update : обрабатывает &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; запрос для обновления существующего экземпляра ресурса&lt;/li&gt;
	&lt;li&gt;destroy : обрабатывает запрос &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; для удаления экземпляра ресурса&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;И три этих:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;index : обрабатывает &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; запрос для отображения коллекции ресурсов&lt;/li&gt;
	&lt;li&gt;new : обрабатывает &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; запрос для получения пустой формы для добавления экземпляра. Как правило используется &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; клиентами&lt;/li&gt;
	&lt;li&gt;edit : обрабатывает &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; запрос для получения формы, заполненной данными текущего ресурса, опять же, как правило используется &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; клиентами.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Названия этих методов имеют большое значение, потому что Rails будет перенаправлять запросы методам с именно такими именами.&lt;/p&gt;
&lt;p&gt;Разумеется, необязательно реализовать все семь методов. Если бизнес модель подразумевает что один из ресурсов предназначен только для чтения, то разумно реализовать для него только методы index и show.&lt;/p&gt;
&lt;p&gt;Вы наверное уже с ужасом думаете о том, как создавать полноценные Rails приложения, учитывая что в Вашем распоряжении только эти семь методов. Первым делом, не беспокойтесь. Если вы на действительно уверены в том, что в Вашей ситуации необходимо ввести еще несколько дополнительных методов, то добавляйте. Но знайте, что это может быть признаком того, что Вы не достаточно хорошо подумали архитектуру приложения и возможно определили не все ресурсы.&lt;/p&gt;
&lt;p&gt;Регулировщик&lt;/p&gt;
&lt;p&gt;Теперь нам нужно понять, как сопоставить &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; и &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; запросы с методами нашего контроллера.&lt;/p&gt;
&lt;p&gt;Обычно название метода, который будет вызван видно в &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. Надеюсь вы помните, как работает стандартный механизм Routing в Rails. Если нет, то вот 5-ти секундный курс, который освежит Вашу память: файл routes.rb содержит правила сопоставления &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; с контроллерами и их методами:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/airports/:action/:id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;airports&amp;#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;В этом примере &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; www.mydomain.comm/airports/open/45 сопоставляется с контроллером (классом) AirportsController и его методом open. В момент вызова метода open, params[:id] будет содержать число 45.&lt;/p&gt;
&lt;p&gt;Но для того чтобы реализовать &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; подход, нужно поступить по-другому. В первую очередь, один и тот же &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; может в зависимости от типа &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; запроса соответствовать разным методам, например &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;/airports/1&lt;/p&gt;
&lt;p&gt;должен вызывать метод show (для отображения аэропорта №1) если был использован запрос &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt;, но в случае запроса &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; должен вызывать метод destroy.&lt;/p&gt;
&lt;p&gt;Раньше в Rails не было возможности определить такие правила с помощью map.connect, но с приходом версии 1.2 появилась одна маленькая, но очень важная фича, суть которой непонятна тем, кто незнаком с &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;airports&amp;#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Выглядит очень коротко, но в то же время очень многое значит, а именно:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;у вас есть ресурс airports (обратите внимание на множественное число, это важно)&lt;/li&gt;
	&lt;li&gt;Вы хотите чтобы Rails использовал &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; соглашения для сопоставления запросов&lt;/li&gt;
	&lt;li&gt;маршрутизация запросов будет происходить не только основываясь на &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;, но и с учетом типа &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; запроса&lt;/li&gt;
	&lt;li&gt;все запросы, связанные с ресурсом airports должны направляться контроллеру AirportsController (заметьте, опять множественное число)&lt;/li&gt;
	&lt;li&gt;все &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; для этого ресурса будут соответствовать &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; соглашениям (об этом чуть позже)&lt;/li&gt;
	&lt;li&gt;в Вашем распоряжении будет набор предопределенных именованных &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; для каждого действия над этим ресурсом&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Пара &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;/тип &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; запроса будет автоматически сопоставлена методам контроллера вот так:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;/airports/ + &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; = create&lt;/li&gt;
	&lt;li&gt;/airports/1 + &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; = show&lt;/li&gt;
	&lt;li&gt;/airports/1 + &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; = update&lt;/li&gt;
	&lt;li&gt;/airports/1 + &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; = destroy&lt;/li&gt;
	&lt;li&gt;/airports/ + &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; = index&lt;/li&gt;
	&lt;li&gt;/airports/new + &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; = new&lt;/li&gt;
	&lt;li&gt;/airports/1;edit + &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; = edit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Замечание. Точка с запятой, которая наверняка бросилась в глаза в &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; для метода edit является стандартом в Rails 1.2.3, но будет заменена на слэш в Rails 2.0.&lt;/p&gt;
&lt;p&gt;Все что Вам осталось сделать, это реализовать семь методов в Вашем контроллере. Остальное за Вас сделает Rails!&lt;/p&gt;
&lt;p&gt;Это еще не все&lt;/p&gt;
&lt;p&gt;Но это еще не все. В Rails 1.2 появился очень изящный генератор scaffold_resource, который способен создать все необходимое для Вашего нового ресурса: код в routes.rb, контроллер со всеми семью методами, &lt;span class=&quot;caps&quot;&gt;RHTML&lt;/span&gt; шаблоны для этих методов и миграцию для создания соответствующей таблицы в базе данных, т.е. все что необходимо для начала.&lt;/p&gt;
&lt;p&gt;И действительно, самое полезное из того что Вы можете сделать для изучения &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; &amp;#8211; это создать новое приложение и сгенерировать ресурс. Создайте базы данных myapp_development и myapp_test, и наберите вот эти команды:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myapp&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myapp&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myapp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scaffold_resource&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;airport&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;designator&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myapp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rake&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:migrate&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Потом запустите сервер ruby script/server  и наберите в браузере localhost:3000/airports. Теперь Вы можете создавать, редактировать и удалять аэропорты, но как все это работает?&lt;/p&gt;
&lt;p&gt;Просто загляните в airport_controller.rb &amp;#8211; весь код находится там, и его на удивление мало. Просмотрите его, потому что  для того чтобы продолжить, необходимо чтобы Вы понимали, что там происходит.&lt;/p&gt;
&lt;p&gt;Потом, посмотрите на rhtml шаблоны и обратите внимание на то, как в них используются сгенерированные именованные &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;, чтобы понять, каким образом входящий запрос связывается с методом контроллера и какой шаблон будет отображен в ответ.&lt;/p&gt;
&lt;p&gt;В коде контроллера есть одна конструкция, которую Вы возможно не видели раньше: блок respond_to, который выглядит немного странно. Это очень важная часть реализации &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; и мы рассмотрим ее более подробно в следующий раз.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>REST Ликбез. Часть 3. Проектирование согласно REST.</title>
   <link href="http://www.taknado.com/2007/8/1/rest-3/"/>
   <updated>2007-08-01T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/8/1/rest-3</id>
   <content type="html">&lt;p&gt;Перевод (подробности &lt;a href=&quot;/2007/8/31/rest-on-rails&quot;&gt;здесь&lt;/a&gt;) статьи &lt;a href=&quot;http://www.softiesonrails.com/2007/4/10/rest-101-part-3-just-call-me-the-repo-man&quot;&gt;Rest 101: Part 3 &amp;#8211; RESTful Design&lt;/a&gt;, автором которой является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ранее мы обсуждали разницу между &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-страницей и ресурсом. Сегодня нам предстоит понять как архитектура, основанная на ресурсах, может быть нам полезна.&lt;/p&gt;
&lt;p&gt;С текущего момента считайте свое приложение не более чем хранилищем ресурсов. Что такое хранилище? &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; &amp;#8211; хороший пример хранилища исходных кодов. MySQL &amp;#8211; хранилище реляционных данных. Позиция хоккейной команды  Chicago в турнирной таблице &lt;span class=&quot;caps&quot;&gt;NHL&lt;/span&gt; &amp;#8211; это доступное только для чтения хранилище некоторой хоккейной статистики.&lt;/p&gt;
&lt;p&gt;Сейчас мне нужно придумать хранилище ресурсов, которое я буду использовать в качестве примера в этой статье.&lt;/p&gt;
&lt;p&gt;Допустим Вы работаете в Softies TransAir и Вам поручили создать программную инфраструктуру компаниии с нуля.&lt;/p&gt;
&lt;p&gt;1. Вам необходим инструмент для занесения информации об авиарейсах. Авиарейс &amp;#8211; это самолет перемещающийся из одного города в другой в определенное время.&lt;br /&gt;
2. Вам необходим &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; интерфейс для сотрудников аэропорта. Вы также хотите, чтобы пассажиры могли проверить статус рейса с мобильного телефоны&lt;br /&gt;
3. Ваш начальник хочет, чтобы Вы реализовали &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;-&lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, который мог бы быть использован сторонними разработчиками для реализации обновления данных на тех самых огромных щитах в здании аэропорта.&lt;/p&gt;
&lt;p&gt;Интересный проект, не так ли? Помните как ранее мы обсуждали традиционный объектно-ориентированный подход? Согласно ему можно взглянуть на описание задачи и выделить существительные (которые в последствии станут объектами) и глаголы (которые станут методами). Только представьте сколько замечательных паттернов вы могли бы здесь применить! Я знаю, Вам просто не терпится нарисовать огромную &lt;span class=&quot;caps&quot;&gt;UML&lt;/span&gt; диаграмму на доске вместе с несколькими диаграммами взаимодействия! И Вы уже видите реализованными методы вроде FlightSchedule.CancelFlight() и Flight.Delay().&lt;/p&gt;
&lt;p&gt;Уж простите. Поскольку Вы решили идти дорогой &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;, то большая часть архитектуры уже продумана за Вас. По сути все что Вам остается сделать, это определить ресурсы.&lt;/p&gt;
&lt;p&gt;И пожалуй я повторю на тот случай если Вы не услышали меня за шуршанием своих маркеров по доске потому что это действительно важно.&lt;/p&gt;
&lt;p&gt;Просто определите ресурсы.&lt;/p&gt;
&lt;p&gt;В нашем примере я могу сразу выделить несколько ключевых существительных: самолеты, аэропорты и авиарейсы. Возможно со временем появятся еще, но для начала этого достаточно.&lt;/p&gt;
&lt;p&gt;Каким образом клиентское приложение будет обращатсья ко всем этим ресурсам? Для это были изобретены &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; (Кстати, вы же знаете что означает L в &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;?) Идентификатор каждого ресурса построен по простому шаблону. Например:&lt;/p&gt;
&lt;p&gt;/airports &amp;#8211; список аэропортов&lt;br /&gt;
/airplanes &amp;#8211; список самолетов&lt;br /&gt;
/flights &amp;#8211; список авиарейсов&lt;/p&gt;
&lt;p&gt;и:&lt;/p&gt;
&lt;p&gt;/airports/ord &amp;#8211; аэропорт Chicago O&amp;#8217;Hare&lt;br /&gt;
/airplanes/ZJ3543 &amp;#8211; самолет с серйиным номером ZJ3543&lt;br /&gt;
/flights/451 &amp;#8211; авиарейс #451&lt;/p&gt;
&lt;p&gt;Четыре метода&lt;/p&gt;
&lt;p&gt;Хорошо, Вы определились с ресурсами. &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; в свою очередь предлагает четыре метода (глагола &amp;#8211; если проводить параллель с ООП), которые каждый из Ваших ресурсов может имплементировать.&lt;/p&gt;
&lt;p&gt;GET. Я хочу получить представление одного из ресурсов в режиме только чтения.&lt;br /&gt;
&lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;. У меня есть новый ресурс который я хочу добавить в хранилище.&lt;br /&gt;
&lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt;. Я хочу обновить ресурс который уже присутствует в хранилище.&lt;br /&gt;
&lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt;. Я хочу удалить ресурс из хранилища.&lt;/p&gt;
&lt;p&gt;Ничего не напоминает? В &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; &amp;#8211; это команда &amp;#8216;checkout&amp;#8217; или &amp;#8216;update&amp;#8217;. &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; &amp;#8211; это команда &amp;#8216;add&amp;#8217;. &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; это команда &amp;#8216;commit&amp;#8217;. &amp;#8216;&lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; &amp;#8211; это собственно команда &amp;#8217;delete&amp;#8217;. Если сравнить с MySQL, &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; &amp;#8211; это запрос &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; &amp;#8211; это &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; &amp;#8211; это &lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt; и &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; &amp;#8211; снова просто &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Теперь когда мы определились с ресурсами и методами можно заканчивать проектирование и переходить к реализации.&lt;/p&gt;
&lt;p&gt;Вызов методов при помощи &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;В &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-приложениях в качестве средства обмена данными между сервером и клиентом используется &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;. Теперь мы можем подкорректировать неточное описание того, как работает браузер, данное в первой части. Что же происходит на самом деле когда мы набираем &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; в адресной строке? Браузер составляет &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;  запрос для вызова метода &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; ресурса, идентифицируемого по &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;, который мы ввели.&lt;/p&gt;
&lt;p&gt;Вы так же можете вызвать метод &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;, но только в том случае, если на странице есть форма (Да, не совсем так, благо есть &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt;, но   давайте пока остановимся на этом). Формы могут отправлять данные по определенному &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. Когда вы подтверждаете отправку формы, браузер вызывает метод &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; у ресурса, расположенного по &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; и передает ему данные, которые являются значениями атрибутов ресурса который он хочет создать или обновить.&lt;/p&gt;
&lt;p&gt;К сожалению Вы не можете вызвать &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; или &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; стандартными средствами &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;. Тем не менее каждый &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; сервер в мире готов принять вызов этих методов и для того чтобы их вызвать необходимо придумать некий способ показать серверу что Вы пытаетесь обратиться к &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; или &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Таким образом Вы можете связать свой &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; с типами запросов &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;, но из-за того что средствами &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; нельзя заставить браузер делать запросы &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; и &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt;, сервер и клиент должны договориться о том, как они они будут эмулировать вызов этих методов.&lt;/p&gt;
&lt;p&gt;В этой статье мы завершили проектирование и в следующий раз перейдем непосредственно к написанию кода.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>REST Ликбез. Часть 2. Миллионы API.</title>
   <link href="http://www.taknado.com/2007/7/31/rest-2/"/>
   <updated>2007-07-31T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/31/rest-2</id>
   <content type="html">&lt;p&gt;Перевод (подробности &lt;a href=&quot;/2007/8/31/rest-on-rails&quot;&gt;здесь&lt;/a&gt;) статьи  &lt;a href=&quot;http://www.softiesonrails.com/2007/4/3/rest-101-part-2-a-million-apis&quot;&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; 101: Part 2 &amp;#8211; A Million APIs&lt;/a&gt;, автором которой является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;В предыдущей статье я пытался убедить Вас в том, что &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; &amp;#8211; это совокупность ресурсов, а не &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-страниц. Сегодня мы еще на шаг приблизимся к пониманию &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Объектно ориентированный подход&lt;/p&gt;
&lt;p&gt;Если Вы когда-либо занимались ООП, то скорее всего действовали примерно по такому плану:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Необходимо описать, что будет делать Ваша программа.&lt;/li&gt;
	&lt;li&gt;Существительные в получившимся описании &amp;#8211; это классы.&lt;/li&gt;
	&lt;li&gt;Глаголы &amp;#8211; это методы классов.&lt;/li&gt;
	&lt;li&gt;Для того чтобы программа решала поставленную задача необходимо, чтобы существительные вызывали методы других существительных.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Звучит разумно, и именно так я программировал долгое время. Такой подход часто называется &amp;#8220;&lt;span class=&quot;caps&quot;&gt;RPC&lt;/span&gt;&amp;#8221;-стилем. Я не совсем понимаю причем здесь &amp;#8220;удаленность&amp;#8221; (&lt;span class=&quot;caps&quot;&gt;RPC&lt;/span&gt; &amp;#8211; Remote Procedure Call &amp;#8211; Удаленный вызов процедур), но знаю, что это является традиционным способом проектирования объектно-ориентированных программ. Это отличный способ, но &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; работает не так. Почему?&lt;/p&gt;
&lt;p&gt;Представьте, что на сейчас 1992 год и 3 крупных компании разработали 3 разных онлайн программных продукта: один для покупки книг,  другой для бронирования авиабилетов и третий для просмотра аэрофотографий, сделанных в воздухе над Землей. Каждая из компаний создавала свой продукт используя классический объектно-ориентированный подход, описанный выше. Они так-же предусмотрели возможность использования своих продуктов другими приложениями, реализовав для каждого свой собственный &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Теперь представьте что Ваша задача &amp;#8211; создать инструмент, который использовал бы все эти 3 приложения одновременно.&lt;/p&gt;
&lt;p&gt;Вам пришлось бы изучить 3 различных &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; и я готов поспорить что у Вас были бы элементы пользовательского интерфейса, напрямую взаимодействующие с методами этих &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. Но этого звучит логично, так? Как бы еще Вы могли это сделать? К тому же, &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; всего три и Вы, конечно, знаете несколько хороших книг из которых можно почерпнуть паттерны для того тобы упростить архитектуру (и выглядеть круто в глазах сослуживцев). Но что если бы Вам пришлось иметь дело с миллионами &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;?&lt;/p&gt;
&lt;p&gt;Давайте вновь вспомним о браузере. Когда Вы устанавливаете его на на свой компьютер, он не обладает данными о том, какие сайты Вы собираетесь посещать. Он способен отображать любой сайт который Вы заходите, и более того, с его помощью Вы можете покупать музыку, бронировать авиабилеты и рассматривать свой дом на фотографиях из космоса.&lt;/p&gt;
&lt;p&gt;Это магия? Задумайтесь над тем, как обстояло бы дело, если бы у каждого сайта был свой &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. Для того чтобы купить книгу на Amazon браузеру необходимо было бы уметь вызывать Amazon.Buy(), а когда я нажимал бы кнопку &amp;#8220;Просмотреть список авиарейсов&amp;#8221;, обращаться к UnitedAirlines.CheckFlights(). Совершенно невозможно создать инструмент, котрый бы использовал миллионы различных &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Именно поэтому &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; не основывается на &lt;span class=&quot;caps&quot;&gt;RPC&lt;/span&gt;. В основе архитектуры &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; лежат ресурсы, т.е. &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Согласно Wikipedia, &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; &amp;#8211; это Representational State Transfer. Чтобы это не значило, смысл в том, что вместо существительных со своим определенным набором глаголов, каждое существительное (с текущего момента будем называть их ресурсами) обладает одним и тем же конечным набором глаголов (т.е. конечный список действий, которые над ними можно произвести). Другими словами у всех ресурсов единый &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. Основные методы &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; позволяют любому клиенту:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Получить ресурс только для чтения.&lt;/li&gt;
	&lt;li&gt;Создать новый ресурс.&lt;/li&gt;
	&lt;li&gt;Обновить существующий ресурс.&lt;/li&gt;
	&lt;li&gt;Удалить ресурс.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Но постойте! Каким из этих методов я смогу &amp;#8220;купить книгу&amp;#8221;? Каким &amp;#8220;найти авиарейсы из Чикаго в Нью-Йорк в следующий вторник&amp;#8221;? Каким изменить масштаб карты с уровня &amp;#8220;города&amp;#8221; до уровня &amp;#8220;улицы&amp;#8221;? Какой из этих методов позволит посетителю авторизироваться на сайте?&lt;/p&gt;
&lt;p&gt;На эти вопросы мы ответим в следующий раз. Но я думаю, что, возможно, у Вас уже есть ответы, если вы действительно перестали думать о &amp;#8220;покупке книги&amp;#8221; как о &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-странице и пытаетесь определить какой ресурс используется Вами в этом случае. До встречи.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>REST Ликбез. Часть 1. Ресурсы.</title>
   <link href="http://www.taknado.com/2007/7/30/rest-1/"/>
   <updated>2007-07-30T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/30/rest-1</id>
   <content type="html">&lt;p&gt;Перевод (подробности &lt;a href=&quot;/2007/8/31/rest-on-rails&quot;&gt;здесь&lt;/a&gt;) статьи &lt;a href=&quot;http://www.softiesonrails.com/2007/3/28/rest-101-part-1-understanding-resources&quot;&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; 101: Part 1 &amp;#8211; Understanding Resources&lt;/a&gt;, автором которой является &lt;a href=&quot;http://jeffcohenonline.com/&quot;&gt;Jeff Cohen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Лично мне стоило больших усилий понять, что такое &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;. Может быть, потому что большую часть жизни я разрабатывал клиент-серверные приложеня, а не &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-сайты, или, потому что в момент знакоства с &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; я изучал принципы &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; программирования, Ruby, и Rails одновременно. Когда я поехал на первую конференцию, посвященную Rails, там все  говорили только о &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;, и я, чтобы не казаться придурком, улыбался и делал вид, что в курсе дела, хотя совершенно не понимал о чем речь.&lt;/p&gt;
&lt;p&gt;Если Вы, как и я когда-то, пытаетесь понять что же такое &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; и как применить эту концепцию в Rails, то эта серия статей для Вас.&lt;/p&gt;
&lt;p&gt;Эксперты в &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; и &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; обязательно будут придираться к тому, насколько я упрощаю терминологию чтобы сфокусироваться на самой теме, но я не желаю этого слышать, потому как эта серия написана не для экспертов :)&lt;/p&gt;
&lt;p&gt;Часть 1.&lt;/p&gt;
&lt;p&gt;Итак, начнем с самого начала. Как работает браузер? Прежде чем я начал создавать сайты на Rails, я думал что это происходит примерно так:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Я набираю &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; в адресной строке, либо нажимаю на ссылку.&lt;/li&gt;
	&lt;li&gt;Браузер выполняет “HTTP запрос” (чтобы это не значило) и получает &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; в ответ.&lt;/li&gt;
	&lt;li&gt;Браузер отображает &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; на экране.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Я никогда особо не задумывался о том, как работают, например, формы, а просто считал, что это один из вариантов вышеописанной схемы.&lt;/p&gt;
&lt;p&gt;На самом деле, протокол &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; содержит точные указания о том, как браузер должен отправлять запросы серверу. &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; принципиально отличается от &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, который являясь языком разметки предназначен для отображения содержимого страницы. В то время как &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; помимо банального получения &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; страницы и отправки данных формы позволяет выполнять и другие действия, а именно он поддерживает 8 типов запросов. Наиболее известными являются 2:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Запрос “GET”: используется для получения содержимого какого-либо ресурса в сети. Ресурс обладает уникальным идентификатором – &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;Запрос “POST”: используется для отправки данных на &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; для создания нового ресурса.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Часть 2.&lt;/p&gt;
&lt;p&gt;Первым шагом к пониманию &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; для меня стало изменение представления о &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;. &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; – это совокупность ресурсов, но не страниц. Я хочу акцентировать на этом внимание и вот почему.&lt;/p&gt;
&lt;p&gt;Вчера я отправился на amazon.com и просмотрел несколько товаров, которые мне было бы интересно купить. Еще я прочитал несколько статей из Wikipedia и заголовки свежих новостей на сайте &lt;span class=&quot;caps&quot;&gt;CNN&lt;/span&gt;. Потом я познакомился с текущим положением хоккейной команды Чикаго в турнирной таблице &lt;span class=&quot;caps&quot;&gt;NHL&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Чтобы понять &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; Вам придется перестать думать обо всех этих вещах как о &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-страницах. Например, статья в Wikipedia. Это не просто страница, это ресурс (в моем случае – краткая биография Архимеда). Я использовал браузер чтобы получить доступ к этому ресурсу, и он запросил представление ресурса в формате &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, потому что это та форма, в которой браузеры отображают ресурсы.&lt;/p&gt;
&lt;p&gt;Но разве статья про Архимеда не является &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-страницей? Нет. Я запросил представление ресурса из Wikipedia в формате &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, ресурса который может быть идентифицирован по &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; ”//en.wikipedia.org/wiki/Archimedes”. Wikipedia могла бы отобразить ресурс в любом другом виде – в качестве &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; документа, или возможно &lt;span class=&quot;caps&quot;&gt;JPG&lt;/span&gt; изображения, или даже предложить несколько форматов на выбор. Но Firefox отправил &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; запрос на получение этого ресурса в формате &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; и ответ был соответствующим.&lt;/p&gt;
&lt;p&gt;Другой пример: бронь авиабилета &amp;#8211; это ресурс, предоставляемый компанией United Airlines. Они позволяют мне обратиться к этому ресурсу разными способами: как к &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; странице на их сайте, либо они могут отправить информацию о брони в качестве текстового сообщения на мобильный телефон, также они могут отправить мне эту информацию на email, а еще я могу позвонить им по телефону. Один и тот же ресурс, но разные представления.&lt;/p&gt;
&lt;p&gt;Надеюсь, теперь это очевидно: моя бронь – не просто &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt;-страница. Это реальный ресурс, который может быть отображен при помощи &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; и поэтому я могу воспользоваться браузером и просмотреть информацию о моей брони.&lt;/p&gt;
&lt;p&gt;Часть 3.&lt;/p&gt;
&lt;p&gt;Теперь, когда я убедил Вас, что &lt;span class=&quot;caps&quot;&gt;WEB&lt;/span&gt; – это на самом деле огромное хранилище ресурсов, которые могут быть отображены различными способами, и &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; &amp;#8211; это всего лишь один из этих способов, я хотел бы предоставить Вашему вниманию еще одну концепцию. Ресурс – это не обязательно единичный элемент, как, например, биографическая статья или турнирная таблица. Некоторые ресурсы представляют собой совокупность других ресурсов. Ресурсом может быть список праздников, список друзей или несколько постов в блоге.&lt;/p&gt;
&lt;p&gt;В следующей статье я собираюсь описать, как &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; позволяет создавать, читать, обновлять и удалять ресурсы.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Overriding Rake Tasks</title>
   <link href="http://www.taknado.com/2007/7/30/overriding-rake-tasks/"/>
   <updated>2007-07-30T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/30/overriding-rake-tasks</id>
   <content type="html">&lt;p&gt;It seems that I&amp;#8217;m lucky cause the project I&amp;#8217;m currently working on forces me to deal with non-typical problems again and again. This time I need to override one of the default Rails Rake tasks behaviour. For some reason I thought that I&amp;#8217;ll simply be able to do it somehow, but it appeared that Rake doesn&amp;#8217;t allow that and I&amp;#8217;ve ended up with another plugin :)&lt;/p&gt;
&lt;p&gt;I won&amp;#8217;t describe why I needed to override Rake tasks right now, I&amp;#8217;m going to post another article about it latter, let&amp;#8217;s just take it as a matter of course for now.&lt;/p&gt;
&lt;p&gt;First of all I&amp;#8217;ve tried to simply define a new task with the same name as the existing one and thought that it will work, but Rake adds the new task to the queue in this case and runs both (the new one after the original one).&lt;/p&gt;
&lt;p&gt;Then I&amp;#8217;ve tried to read more about Rake and found out that one can add &amp;#8220;prerequisites&amp;#8221; for the tasks (even for exisitng ones) like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;pre_test_task1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pre_test_task2&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;While that&amp;#8217;s very helpfull, it doesn&amp;#8217;t solve my problem. As usual I&amp;#8217;ve googled for a solution and found &lt;a href=&quot;http://matthewbass.com/2007/03/07/overriding-existing-rake-tasks/&quot;&gt;Matthew Bass&amp;#8217;s blog post&lt;/a&gt;. Actually Mattew described a working solution, but I didn&amp;#8217;t like the way it looked. To override a task one have to add the new tasks to the Rakefile like this (we&amp;#8217;re overriding Rails &amp;#8220;test&amp;#8221; task):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;remove_task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#new task code here&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I didn&amp;#8217;t like the idea of adding new tasks to the Rakefile and the &amp;#8220;remove_task&amp;#8221; method call before each task. So I&amp;#8217;ve spent a couple of hours   messing with Rake sources and finally written an &amp;#8220;override_task&amp;#8221; method that actually deleted existing task with the given name and defined a new one. It can be used like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;override_task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#new task code here&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can put this in you app&amp;#8217;s lib/tasks as usual, or add it to one of your plugins&amp;#8217; tasks. It works with a namespace too of course:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;override_task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:migrate&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#new migration code here &lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then, I thought if it could be made as a plugin. In order to make it work, the code written should be loaded before the tasks and it means that Rakefile should be modified to load it. I&amp;#8217;ve recently messed with &lt;a href=&quot;http://jarmark.org/projects/app-config/&quot;&gt;app_config plugin by Daniel Owsiański&lt;/a&gt; and noticed the way it adds a line to environment.rb during installation. I&amp;#8217;ve simply copied the idea and the plugin was ready! During installation it adds a line to the Rakefile that loads the plugin itself.&lt;/p&gt;
&lt;p&gt;To play with it do the usual&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;script/plugin install git://github.com/eugenebolshakov/override_rake_task.git
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Update: Thanks to Doug for the patch that makes it compatible with Rake 0.8.1+&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rake Task to Display SVN Commits by User</title>
   <link href="http://www.taknado.com/2007/7/26/rake-task-to-display-svn-commits-by-user/"/>
   <updated>2007-07-26T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/26/rake-task-to-display-svn-commits-by-user</id>
   <content type="html">&lt;p&gt;At my current job I&amp;#8217;m being asked to send a list of trac tickets I&amp;#8217;ve been working on in the previous 2 weeks. After reading &lt;a href=&quot;http://www.rails.cz/articles/2006/11/01/layout-with-svn-revision&quot;&gt;this post&lt;/a&gt; I figured out that it can be easily done with Rake (well, as everything else you can dream about).&lt;/p&gt;
&lt;p&gt;Since we&amp;#8217;re using an svn hook that adds notes to the related trac tickets on commit, each revision associated with a ticket has its number in the comments. So all I (Rake task) have to do is to collect all my commit commets, pull ticket numbers from them (typical commit comment can look like this: &amp;#8220;refs #786&amp;#8221;) and display a list, ordered by date.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t play with command line svn client much previously, but when I&amp;#8217;ve started to write the task I&amp;#8217;ve figured out that we can get the svn log in xml using the &amp;#8220;&amp;#8212;xml&amp;#8221; option. Even better!&lt;/p&gt;
&lt;p&gt;So I&amp;#8217;ve ended up with this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:svn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:log&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Displays commints by user in the specified period of time. Usage: rake svn:log:by_user USER=username PASSWORD=pass [URL=repo_url] PERIOD=period_option. Where valid period_options: m - current month, 2w - previous 2 working weeks (monday - friday)&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:by_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            
      &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;URL&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;period&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;m&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;2w&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PERIOD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PERIOD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;2w&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#USER parameter is mandatory&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;use rake:svn:log:by_user USER=svn_username&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;USER&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      

      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;period&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;m&amp;#39;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beginning_of_month&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;end_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;2w&amp;#39;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beginning_of_week&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;end_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beginning_of_week&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;#datetime format used by svn log&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;TF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;%Y-%m-%d %H:%M:%S +0000&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#we&amp;#39;ll use this var to store commits for each day&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;days&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
      
      &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rexml/document&amp;#39;&lt;/span&gt; 
      
      &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;REXML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`svn log &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; --xml -r &amp;quot;{&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;}:{&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;}&amp;quot; --username &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; --password &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each_element&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;#save each revision entry to a hash&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;revision&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;log_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each_element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log_detail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log_detail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log_detail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
      
      &lt;span class=&quot;c1&quot;&gt;#is it my revision?&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;day&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;%y.%m.%d&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#for each day we want a list of trac tickets affected or revision number&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#trac tickets numbers are included in the comment like this: #687&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#so we&amp;#39;ll try to find such numbers using regexp&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#if there are no tickets numbers we&amp;#39;ll simply use revision number like this: [1235]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tickets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/#\d+/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tickets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tickets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tickets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
      &lt;span class=&quot;c1&quot;&gt;#and we simply output all commits day by day&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The task takes 4 parameters: &lt;span class=&quot;caps&quot;&gt;USER&lt;/span&gt; (mandatory) &amp;#8211; well, obvious, &lt;span class=&quot;caps&quot;&gt;PASSWORD&lt;/span&gt; (mandatory), &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; (optional) &amp;#8211; can be provided if rails app is not a working copy of repository you&amp;#8217;d like to get a log from and &lt;span class=&quot;caps&quot;&gt;PERIOD&lt;/span&gt; &amp;#8211; &amp;#8220;m&amp;#8221; to use the revisions made in this month only and &amp;#8220;2w&amp;#8221; (default) to use revisions made in the previous 2 working weeks.  So I can run it like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;rake svn:log:by_user &lt;span class=&quot;nv&quot;&gt;USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;eugene.bolshakov &lt;span class=&quot;nv&quot;&gt;PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;secret &lt;span class=&quot;nv&quot;&gt;PERIOD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;m
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and get something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;...
07.07.23 | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2256&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2264&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2265&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
07.07.24 | &lt;span class=&quot;c&quot;&gt;#787, #801, #783&lt;/span&gt;
07.07.25 | &lt;span class=&quot;c&quot;&gt;#786, #823&lt;/span&gt;
07.07.26 | &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2346&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
...
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The numbers with sharp are ticket numbers and those in square brackets are the revision numbers. They are displayed if the revision is not related to any trac ticket. Yeah, I know it could be done easier with xpath, but my knowledge of it is poor :(&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rake Task to Clear Expired Session Files</title>
   <link href="http://www.taknado.com/2007/7/25/rake-task-to-clear-expired-session-files/"/>
   <updated>2007-07-25T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/25/rake-task-to-clear-expired-session-files</id>
   <content type="html">&lt;p&gt;Perhaps some guys who came to Rails from &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; expected session expiry to be handled automatically. But in Rails we have to deal with it ourselves. There&amp;#8217;s an &lt;a href=&quot;http://www.rorsecurity.info/2007/04/10/ruby-on-rails-sessions-introduction-and-expiry/&quot;&gt;awesome article on the topic&lt;/a&gt;. The main idea is that we need to clear expired sessions which were not accessed for some time and the ones which were created a long time ago. I&amp;#8217;ve tried to find a ready-made script for this purpose, but found the ones that deal with database based sessions only, so decided to write it myself.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;find&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:tmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sessions&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Clear expired sessions&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:clear_expired&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ctime&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;atime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;atime&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Find&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RAILS_ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/tmp/sessions/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FileTest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?.&lt;/span&gt;
            &lt;span class=&quot;no&quot;&gt;Find&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prune&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ago&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;atime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ago&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It can be run with 2 optional parameters: &amp;#8220;atime&amp;#8221;, which defines the time in minutes that will be compared against the last access time of a session file and &amp;#8220;ctime&amp;#8221; which defines the time in minutes that will be compared against the creation time of a session file. The default values are: ctime = 120 (minutes) and atime = 20 (miuntes) which means that the session files not accessed in the last 20 minutes and created earlier than 2 hours ago will be removed when the script runs.&lt;/p&gt;
&lt;p&gt;You can run it like this (I&amp;#8217;m overriding default time parameters in the example):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;rake tmp:sessions:clear_expired &lt;span class=&quot;nv&quot;&gt;atime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;15 &lt;span class=&quot;nv&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;60
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Of course you&amp;#8217;ll set up a cron to run the script periodiacally and clear expired sessions for you, but please note that the actuall maximum session lifetime will be atime + the time between 2 script runs.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Custom Configuration Info in Rails</title>
   <link href="http://www.taknado.com/2007/7/25/custom-configuration-info-in-rails/"/>
   <updated>2007-07-25T00:00:00+04:00</updated>
   <id>http://www.taknado.com/2007/7/25/custom-configuration-info-in-rails</id>
   <content type="html">&lt;p&gt;I think most applications deal with some kind of configuration parameters like admin emails, directory paths or whatever. Sometimes having a bunch of constants in environment.rb is fine, but when you have several developers working on a project and each of them may have their own values and can add new parameters you need a clean solution to handle that.&lt;/p&gt;
&lt;p&gt;The common practice is to have an &amp;#8220;example&amp;#8221; config file under version control (like database.example.yml in mephisto) which is used by all developers to create their local files with custom values. That works OK until someone adds a new parameter to the example file and some careless developer (me) doesn&amp;#8217;t notice it in the svn logs, forgets to update his local file and gets a broken application. So I thought that I need a file under version control with default values which is actually used by the application and an ability to have another file with local values that will override the default.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve googled for a ready-made solution and found &lt;a href=&quot;http://kpumuk.info/ruby-on-rails/flexible-application-configuration-in-ruby-on-rails/lang-pref/en/&quot;&gt;this one&lt;/a&gt; which I liked, but as I&amp;#8217;ve just said I also wanted to override the default settings in a local file and also wanted yml file to be parsed with &lt;span class=&quot;caps&quot;&gt;ERB&lt;/span&gt; so that I could use Ruby in it (for example if I needed to use RAILS_ROOT to define some path). And so I&amp;#8217;ve ended up with my first rails plugin :)&lt;/p&gt;
&lt;p&gt;The plugin allows you to have a config.yml file with a &amp;#8220;common&amp;#8221; section that contains all configuration parameters with their default values and a section for each Rails environment (like development, test, production or your custom one) where you can override the values from the common section. Just put this file under version control, update it with new parameters and all developers will have it with the next update. If someone needs his own specific values, he can simply create a config.local.yml file and override any value there, again having a &amp;#8220;common&amp;#8221; section and a section for each environment. Nothing is mandatory (files, sections) &amp;#8211; you just have what you really need.&lt;/p&gt;
&lt;p&gt;An example of a config file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;common&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;admin_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml_rpc_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;media_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RAILS_ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/tmp/me&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dia&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml_rpc_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml_rpc_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8008&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then, in the application you can use the config parameters like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Conf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml_rpc_url&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;So it means that you&amp;#8217;ve got a Conf object which holds all the configuration parameters defined. It doesn&amp;#8217;t allow to change the values in the application code, &lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; (so that a typo in a if statement won&amp;#8217;t cause weird errors :)).&lt;/p&gt;
&lt;p&gt;You can give it a try if you like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;script/plugin install git://github.com/eugenebolshakov/app_config.git
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Comments and suggestions are welcome of course ;)&lt;/p&gt;
&lt;p&gt;Update: I&amp;#8217;ve renamed the configuration variable from Config to Conf.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
