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

<channel>
	<title>Jetpack Flight Log &#187; rails</title>
	<atom:link href="http://jetpackweb.com/blog/tags/rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://jetpackweb.com/blog</link>
	<description>Rock{et}ing the interweb</description>
	<lastBuildDate>Sun, 12 Jun 2011 17:51:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Rails 2.3.4 and SWFUpload &#8211; Rack Middleware for Flash Uploads that Degrade Gracefully</title>
		<link>http://jetpackweb.com/blog/2009/10/21/rails-2-3-4-and-swfupload-rack-middleware-for-flash-uploads-that-degrade-gracefully/</link>
		<comments>http://jetpackweb.com/blog/2009/10/21/rails-2-3-4-and-swfupload-rack-middleware-for-flash-uploads-that-degrade-gracefully/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 05:24:15 +0000</pubDate>
		<dc:creator>Brian Racer</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[swfobject]]></category>
		<category><![CDATA[swfupload]]></category>

		<guid isPermaLink="false">http://jetpackweb.com/blog/?p=523</guid>
		<description><![CDATA[Browser upload controls have been pretty much the same for years. They are very difficult to style, and do not look consistent across browsers. Perhaps the biggest issue with them is they provide no feedback to the user about how long the submission will take. One alternative is to use Flash for the uploads. There [...]]]></description>
			<content:encoded><![CDATA[<p>Browser upload controls have been pretty much the same for years. They are very difficult to style, and do not look consistent across browsers. Perhaps the biggest issue with them is they provide no feedback to the user about how long the submission will take. One alternative is to use Flash for the uploads. There are numerous libraries available, I like <a href="http://swfupload.org/" target="_blank">SWFUpload</a>. Since the reason you are here is probably because you can&#8217;t get it working in Rails, I&#8217;m going to try and help you deal with the quirks associated with using Flash and Rails together.</p>
<p>It used to be you would monkeypatch the CGI class to get Flash uploaders to work due to issues with Flash. With the introduction of <a href="http://rack.rubyforge.org/" target="_blank">Rack</a> in Rails 2.3 things now work quite differently. What we will do is create some rack middleware to intercept traffic from Flash to deal with it&#8217;s quirks. I have created a small example application of an mp3 player and uploader. You will probably want to download it, as it contains a few files not displayed in this article. You can clone it from the <a href="http://github.com/anveo/swfupload_demo" target="_blank">github project page</a>.</p>
<p>First lets create a simple Song model:</p>

<div class="wp_syntax"><div class="code"><pre class="bash">.<span class="sy0">/</span>script generate model Song title:string artist:string length_in_seceonds:integer track_file_name:string track_content_type:string track_file_size:integer</pre></div></div>

<p><i>title</i>, <i>artist</i>, and <i>length_in_seconds</i> are meta-data we will pull from the ID3 tags of the uploaded mp3 file, and the rest will be used by <a href="http://www.thoughtbot.com/projects/paperclip" target="_blank">Paperclip</a> to handle the attachment. Lets add the paperclip attachment and a few simple validations to our new Song model:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="kw1">class</span> Song <span class="sy0">&lt;</span> <span class="re2">ActiveRecord::Base</span>
&nbsp;
  has_attached_file <span class="re3">:track</span>,
                    <span class="re3">:path</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;:rails_root/public/assets/:attachment/:id_partition/:id/:style/:basename.:extension&quot;</span>,
                    <span class="re3">:url</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;/assets/:attachment/:id_partition/:id/:style/:basename.:extension&quot;</span>
&nbsp;
  validates_presence_of <span class="re3">:title</span>, <span class="re3">:artist</span>, <span class="re3">:length_in_seconds</span>
  validates_attachment_presence <span class="re3">:track</span>
  validates_attachment_content_type <span class="re3">:track</span>, <span class="re3">:content_type</span> <span class="sy0">=&gt;</span> <span class="br0">&#91;</span> <span class="st0">'application/mp3'</span>, <span class="st0">'application/x-mp3'</span>, <span class="st0">'audio/mpeg'</span>, <span class="st0">'audio/mp3'</span> <span class="br0">&#93;</span>
  validates_attachment_size <span class="re3">:track</span>, <span class="re3">:less_than</span> <span class="sy0">=&gt;</span> <span class="nu0">20</span>.<span class="me1">megabytes</span>
&nbsp;
  attr_accessible <span class="re3">:title</span>, <span class="re3">:artist</span>, <span class="re3">:length_in_seconds</span>
&nbsp;
  <span class="kw1">def</span> convert_seconds_to_time
    total_minutes = length_in_seconds <span class="sy0">/</span> <span class="nu0">1</span>.<span class="me1">minutes</span>
    seconds_in_last_minute = length_in_seconds <span class="sy0">-</span> total_minutes.<span class="me1">minutes</span>.<span class="me1">seconds</span>
    <span class="st0">&quot;#{total_minutes}m #{seconds_in_last_minute}s&quot;</span>
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div>

<p>Next comes an upload form and some containers to hold the SWFUploader:</p>

<div class="wp_syntax"><div class="code"><pre class="haml">- form_tag songs_path, :multipart =&gt; true do
  #swfupload_degraded_container
    %noscript= &quot;You should have Javascript enabled for a nicer upload experience&quot;
    = file_field_tag :Filedata
    = submit_tag &quot;Add Song&quot;
  #swfupload_container{ :style =&gt; &quot;display: none&quot; }
    %span#spanButtonPlaceholder
  #divFileProgressContainer</pre></div></div>

<p>The container that holds the SWFUploader will be hidden until we know the user can support it. Initially a standard file upload form will display. A number of things can go wrong, so we need to think about a few levels of degradation here. The user might not have flash installed, the user might have an outdated version of flash, he might not have javascript installed or enabled(which is needed to load the flash), and there may be a problem downloading the flash swf file. Yikes. Luckily using the <a href="http://code.google.com/p/swfobject/" target="_blank">swfobject</a> library we can easily handle all these potential issues.</p>
<p>If the user is missing javascript, he will see the message in the <strong>noscript</strong> tag and be presented a standard upload control.</p>
<p>If the user is missing flash or it is outdated, he will be presented a dialog with an upgrade link. Otherwise he can use the standard upload control.</p>
<p>If  everything goes okey-dokey, then some function handlers we write will hide the the degradation container, and display the flash container.</p>
<p><i>Oh, and just so you know the current version of Flash Player for linux do not fire the event that monitors upload progress, so you will not get the status bar until the upload finishes. No work around for that right now.</i></p>
<p>So lets initialize the SWFUpload via some javascript. Many tutorials out there seem to put the authentication token and session information in the URL, but there are some options with current version of SWFUpload to POST and avoid that.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript"><span class="sy0">:</span>javascript
  SWFUpload.<span class="kw3">onload</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw2">var</span> swf_settings <span class="sy0">=</span> <span class="br0">&#123;</span>
&nbsp;
      <span class="co1">// SWFObject settings</span>
      minimum_flash_version<span class="sy0">:</span> <span class="st0">&quot;9.0.28&quot;</span><span class="sy0">,</span>
      swfupload_pre_load_handler<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        $<span class="br0">&#40;</span><span class="st0">'#swfupload_degraded_container'</span><span class="br0">&#41;</span>.<span class="me1">hide</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        $<span class="br0">&#40;</span><span class="st0">'#swfupload_container'</span><span class="br0">&#41;</span>.<span class="me1">show</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span><span class="sy0">,</span>
      swfupload_load_failed_handler<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp;
      post_params<span class="sy0">:</span> <span class="br0">&#123;</span>
        <span class="st0">&quot;#{session_key_name}&quot;</span><span class="sy0">:</span> <span class="st0">&quot;#{cookies[session_key_name]}&quot;</span><span class="sy0">,</span>
        <span class="st0">&quot;authenticity_token&quot;</span><span class="sy0">:</span> <span class="st0">&quot;#{form_authenticity_token}&quot;</span><span class="sy0">,</span>
      <span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp;
      upload_url<span class="sy0">:</span> <span class="st0">&quot;#{songs_path}&quot;</span><span class="sy0">,</span>
      flash_url<span class="sy0">:</span> <span class="st0">'/flash/swfupload/swfupload.swf'</span><span class="sy0">,</span>
&nbsp;
      file_types<span class="sy0">:</span> <span class="st0">&quot;*.mp3&quot;</span><span class="sy0">,</span>
      file_types_description<span class="sy0">:</span> <span class="st0">&quot;mp3 Files&quot;</span><span class="sy0">,</span>
      file_size_limit<span class="sy0">:</span> <span class="st0">&quot;20 MB&quot;</span><span class="sy0">,</span>
&nbsp;
      button_placeholder_id<span class="sy0">:</span> <span class="st0">&quot;spanButtonPlaceholder&quot;</span><span class="sy0">,</span>
      button_width<span class="sy0">:</span> <span class="nu0">380</span><span class="sy0">,</span>
      button_height<span class="sy0">:</span> <span class="nu0">32</span><span class="sy0">,</span>
      button_text <span class="sy0">:</span> <span class="st0">'&lt;span class=&quot;button&quot;&gt;Select Files &lt;span class=&quot;buttonSmall&quot;&gt;(20 MB Max)&lt;/span&gt;&lt;/span&gt;'</span><span class="sy0">,</span>
      button_text_style <span class="sy0">:</span> <span class="st0">'.button { font-family: Helvetica, Arial, sans-serif; font-size: 24pt; } .buttonSmall { font-size: 18pt; }'</span><span class="sy0">,</span>
      button_text_top_padding<span class="sy0">:</span> <span class="nu0">0</span><span class="sy0">,</span>
      button_text_left_padding<span class="sy0">:</span> <span class="nu0">18</span><span class="sy0">,</span>
      button_window_mode<span class="sy0">:</span> SWFUpload.<span class="me1">WINDOW_MODE</span>.<span class="me1">TRANSPARENT</span><span class="sy0">,</span>
      button_cursor<span class="sy0">:</span> SWFUpload.<span class="me1">CURSOR</span>.<span class="me1">HAND</span><span class="sy0">,</span>
      file_queue_error_handler <span class="sy0">:</span> fileQueueError<span class="sy0">,</span>
      file_dialog_complete_handler <span class="sy0">:</span> fileDialogComplete<span class="sy0">,</span>
      upload_progress_handler <span class="sy0">:</span> uploadProgress<span class="sy0">,</span>
      upload_error_handler <span class="sy0">:</span> uploadError<span class="sy0">,</span>
      upload_success_handler <span class="sy0">:</span> uploadSuccess<span class="sy0">,</span>
      upload_complete_handler <span class="sy0">:</span> uploadComplete<span class="sy0">,</span>
&nbsp;
      custom_settings <span class="sy0">:</span> <span class="br0">&#123;</span>
        upload_target<span class="sy0">:</span> <span class="st0">&quot;divFileProgressContainer&quot;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    <span class="kw2">var</span> swf_upload <span class="sy0">=</span> <span class="kw2">new</span> SWFUpload<span class="br0">&#40;</span>swf_settings<span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span><span class="sy0">;</span></pre></div></div>

<p>You will want to check out the <a href="http://demo.swfupload.org/Documentation/#settingsobject" target="_blank">official SWFUpload docs</a> to understand what all of these variable do. There are <a href="http://github.com/anveo/swfupload_demo/blob/master/public/javascripts/swfupload/handlers.js" target="_blank">many handlers</a> we have to define to handle various events, and if you clone the project you can review them in detail.</p>
<p>We also need to set styles for the containers that will be generated. You can see the Sass file I created for SWFUpload <a href="http://github.com/anveo/swfupload_demo/blob/master/app/stylesheets/swfupload.sass" target="_blank">here</a>, and <a href="http://github.com/anveo/swfupload_demo/blob/master/app/stylesheets/nifty.sass" target="_blank">another one</a> for Ryan Bates <a href="http://github.com/ryanb/nifty-generators" target="_blank">nifty_generators</a>.</p>
<p>Another quirk we have to be aware of when dealing with flash uploads is that everything gets a content-type of an octet stream. We will use the <a href="http://mime-types.rubyforge.org/" target="_blank">mime-types</a> library to identify it for validation. Keep in mind it only uses the extension to determine the file type. (<i>I haven&#8217;t tested it yet, but I believe <a href="http://github.com/mattetti/mimetype-fu" target="_blank">mimetype-fu</a> will actually check file-data and magic numbers</i>). By default SWFUpload calls the file parameter &#8216;Filedata&#8217;.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby">  <span class="kw1">def</span> create
    <span class="kw3">require</span> <span class="st0">'mp3info'</span>
&nbsp;
    mp3_info = Mp3Info.<span class="me1">new</span><span class="br0">&#40;</span>params<span class="br0">&#91;</span><span class="re3">:Filedata</span><span class="br0">&#93;</span>.<span class="me1">path</span><span class="br0">&#41;</span>
&nbsp;
    song = Song.<span class="me1">new</span>
    song.<span class="me1">artist</span> = mp3_info.<span class="me1">tag</span>.<span class="me1">artist</span>
    song.<span class="me1">title</span> = mp3_info.<span class="me1">tag</span>.<span class="me1">title</span>
    song.<span class="me1">length_in_seconds</span> = mp3_info.<span class="me1">length</span>.<span class="me1">to_i</span>
&nbsp;
    params<span class="br0">&#91;</span><span class="re3">:Filedata</span><span class="br0">&#93;</span>.<span class="me1">content_type</span> = <span class="re2">MIME::Types</span>.<span class="me1">type_for</span><span class="br0">&#40;</span>params<span class="br0">&#91;</span><span class="re3">:Filedata</span><span class="br0">&#93;</span>.<span class="me1">original_filename</span><span class="br0">&#41;</span>.<span class="me1">to_s</span>
    song.<span class="me1">track</span> = params<span class="br0">&#91;</span><span class="re3">:Filedata</span><span class="br0">&#93;</span>
    song.<span class="me1">save</span>
&nbsp;
    render <span class="re3">:text</span> <span class="sy0">=&gt;</span> <span class="br0">&#91;</span>song.<span class="me1">artist</span>, song.<span class="me1">title</span>, song.<span class="me1">convert_seconds_to_time</span><span class="br0">&#93;</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">&quot; - &quot;</span><span class="br0">&#41;</span>
  <span class="kw1">rescue</span> Mp3InfoError <span class="sy0">=&gt;</span> e
    render <span class="re3">:text</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;File error&quot;</span>
  <span class="kw1">rescue</span> <span class="kw4">Exception</span> <span class="sy0">=&gt;</span> e
    render <span class="re3">:text</span> <span class="sy0">=&gt;</span> e.<span class="me1">message</span>
  <span class="kw1">end</span></pre></div></div>

<p>Another annoyance with flash uploads is that it doesn&#8217;t send cookie data. That is why we are sending the session information in the POST data. We will intercept requests from Flash, check for the session key, and if so inject it into the cookie header. We can do this with some pretty simple middleware.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="kw3">require</span> <span class="st0">'rack/utils'</span>
&nbsp;
<span class="kw1">class</span> FlashSessionCookieMiddleware
  <span class="kw1">def</span> initialize<span class="br0">&#40;</span>app, session_key = <span class="st0">'_session_id'</span><span class="br0">&#41;</span>
    <span class="re1">@app</span> = app
    <span class="re1">@session_key</span> = session_key
  <span class="kw1">end</span>
&nbsp;
  <span class="kw1">def</span> call<span class="br0">&#40;</span>env<span class="br0">&#41;</span>
    <span class="kw1">if</span> env<span class="br0">&#91;</span><span class="st0">'HTTP_USER_AGENT'</span><span class="br0">&#93;</span> =~ <span class="sy0">/</span>^<span class="br0">&#40;</span>Adobe<span class="sy0">|</span>Shockwave<span class="br0">&#41;</span> Flash<span class="sy0">/</span>
      params = ::<span class="re2">Rack::Request</span>.<span class="me1">new</span><span class="br0">&#40;</span>env<span class="br0">&#41;</span>.<span class="me1">params</span>
      env<span class="br0">&#91;</span><span class="st0">'HTTP_COOKIE'</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span> <span class="re1">@session_key</span>, params<span class="br0">&#91;</span>@session_key<span class="br0">&#93;</span> <span class="br0">&#93;</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">'='</span><span class="br0">&#41;</span>.<span class="me1">freeze</span> <span class="kw1">unless</span> params<span class="br0">&#91;</span>@session_key<span class="br0">&#93;</span>.<span class="kw2">nil</span>?
    <span class="kw1">end</span>
    <span class="re1">@app</span>.<span class="me1">call</span><span class="br0">&#40;</span>env<span class="br0">&#41;</span>
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div>

<p>This is a modified version from code the appears in a few tutorials about flash uploads. It will allow the session information to be in the query string *or* POST data. Next we have to make sure this middleware gets put to use so in <i>config/initializers/session_store.rb</i> add:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="re2">ActionController::Dispatcher</span>.<span class="me1">middleware</span>.<span class="me1">insert_before</span><span class="br0">&#40;</span><span class="re2">ActionController::Base</span>.<span class="me1">session_store</span>, FlashSessionCookieMiddleware, <span class="re2">ActionController::Base</span>.<span class="me1">session_options</span><span class="br0">&#91;</span><span class="re3">:key</span><span class="br0">&#93;</span><span class="br0">&#41;</span></pre></div></div>

<p>And that&#8217;s, uhh, all there is too it. Again, I really suggest you <a href="http://github.com/anveo/swfupload_demo" target="_blank">checkout the example project</a>. It also uses the nifty WordPress Audio Player flash control to play the music you upload!</p>
<p><img src="http://jetpackweb.com/blog/wp-content/uploads/2009/10/Picture-21.png" /><br />
<img src="http://jetpackweb.com/blog/wp-content/uploads/2009/10/Picture-11.png" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jetpackweb.com/blog/2009/10/21/rails-2-3-4-and-swfupload-rack-middleware-for-flash-uploads-that-degrade-gracefully/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Unobtrusive RESTful jQuery</title>
		<link>http://jetpackweb.com/blog/2009/09/09/unobtrusive-restful-jquery/</link>
		<comments>http://jetpackweb.com/blog/2009/09/09/unobtrusive-restful-jquery/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 16:42:32 +0000</pubDate>
		<dc:creator>Brian Racer</dc:creator>
				<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[rest]]></category>

		<guid isPermaLink="false">http://jetpackweb.com/blog/?p=347</guid>
		<description><![CDATA[Many Rails(and non-Rails) web applications these days strive to create RESTful interfaces for their application design. When dealing with Ajax updates through jQuery, this can become somewhat tricky. Since most browsers only implement GET and POST requests, we have to fake it in Rails by sending a parameter called _methd for all PUT and DELETE [...]]]></description>
			<content:encoded><![CDATA[<p>Many Rails(and non-Rails) web applications these days strive to create <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">RESTful</a> interfaces for their application design. When dealing with Ajax updates through jQuery, this can become somewhat tricky. Since most browsers only implement GET and POST requests, we have to fake it in Rails by sending a parameter called <b>_methd</b> for all PUT and DELETE requests. To make things even more complicated, we need to include a token to prevent <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" target="_blank">CSRF</a> attacks.</p>
<p>In Rails 2.x, the default way it generates the javascript to send a a RESTful command via POST request looks something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="html">&lt;a href=&quot;/foos/1&quot; onclick=&quot;if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'VGcSbbdenz7ZCMDWl7LugKC2KFldp7oKdgdvjGyb4Zo='); f.appendChild(s);f.submit(); };return false;&quot;&gt;Destroy&lt;/a&gt; |</pre></div></div>

<p>Yuck. It&#8217;s creating a new form, setting a hidden input fields for the submission method and csrf token, and then submitting it. Not only is it obtrusive, that gets inserted at every location there is a delete or update link. </p>
<p>First lets extend jquery with PUT and DELETE methods. Well call this <strong>jquery.rest.js</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript"><span class="sy0">;</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span>$<span class="br0">&#41;</span><span class="br0">&#123;</span>
  $.<span class="me1">put</span> <span class="sy0">=</span> $.<span class="me1">update</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">&#40;</span>uri<span class="sy0">,</span> data<span class="sy0">,</span> callback<span class="sy0">,</span> type <span class="sy0">=</span> <span class="st0">'json'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>$.<span class="me1">isFunction</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><span class="br0">&#41;</span> callback <span class="sy0">=</span> data<span class="sy0">,</span> data <span class="sy0">=</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
    <span class="kw1">return</span> $.<span class="me1">post</span><span class="br0">&#40;</span>uri<span class="sy0">,</span> $.<span class="me1">extend</span><span class="br0">&#40;</span>data<span class="sy0">,</span> <span class="br0">&#123;</span> _method<span class="sy0">:</span> <span class="st0">'put'</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">,</span> callback<span class="sy0">,</span> type<span class="br0">&#41;</span>
  <span class="br0">&#125;</span>
&nbsp;
  $.<span class="kw1">delete</span> <span class="sy0">=</span> $.<span class="me1">del</span> <span class="sy0">=</span> $.<span class="me1">destroy</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">&#40;</span>uri<span class="sy0">,</span> data<span class="sy0">,</span> callback<span class="sy0">,</span> type <span class="sy0">=</span> <span class="st0">'json'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>$.<span class="me1">isFunction</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><span class="br0">&#41;</span> callback <span class="sy0">=</span> data<span class="sy0">,</span> data <span class="sy0">=</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
    <span class="kw1">return</span> $.<span class="me1">post</span><span class="br0">&#40;</span>uri<span class="sy0">,</span> $.<span class="me1">extend</span><span class="br0">&#40;</span>data<span class="sy0">,</span> <span class="br0">&#123;</span> _method<span class="sy0">:</span> <span class="st0">'delete'</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">,</span> callback<span class="sy0">,</span> type<span class="br0">&#41;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#123;</span><span class="br0">&#41;</span><span class="br0">&#40;</span>jQuery<span class="br0">&#41;</span></pre></div></div>

<p>The previous code will <b>POST</b> data while always including a &#8216;_method&#8217; parameter. Using this code is as simple as a normal jQuery ajax call:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript">$<span class="br0">&#40;</span><span class="st0">'.deletable'</span><span class="br0">&#41;</span>.<span class="me1">click</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $.<span class="kw1">delete</span><span class="br0">&#40;</span><span class="st0">'/videos/delete'</span><span class="sy0">,</span> <span class="br0">&#123;</span>
    <span class="st0">'video_id'</span><span class="sy0">:</span> $<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span>.<span class="me1">attr</span><span class="br0">&#40;</span><span class="st0">'id'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>That example might iterate through all elements with the deletable class, and then sent the <b>DELETE</b> method when clicked.</p>
<p> Now in a Rails app we also need to include the CSRF token in all POST, PUT, and DELETE requests. The way I go about this is to put this at the bottom of my applications layout:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  window.<span class="me1">AUTH_TOKEN</span> <span class="sy0">=</span> <span class="st0">'#{form_authenticity_token}'</span><span class="sy0">;</span>
  $<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ajaxSend</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> request<span class="sy0">,</span> settings<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span><span class="br0">&#40;</span>window.<span class="me1">AUTH_TOKEN</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="st0">&quot;undefined&quot;</span><span class="br0">&#41;</span> <span class="kw1">return</span><span class="sy0">;</span>
    <span class="co1">// IE6 fix for http://dev.jquery.com/ticket/3155</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>settings.<span class="me1">type</span> <span class="sy0">==</span> <span class="st0">'GET'</span> <span class="sy0">||</span> settings.<span class="me1">type</span> <span class="sy0">==</span> <span class="st0">'get'</span><span class="br0">&#41;</span> <span class="kw1">return</span><span class="sy0">;</span>
    settings.<span class="me1">data</span> <span class="sy0">=</span> settings.<span class="me1">data</span> <span class="sy0">||</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span>
    settings.<span class="me1">data</span> <span class="sy0">+=</span> <span class="br0">&#40;</span>settings.<span class="me1">data</span> <span class="sy0">?</span> <span class="st0">&quot;&amp;&quot;</span> <span class="sy0">:</span> <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span> <span class="sy0">+</span> <span class="st0">&quot;authenticity_token=&quot;</span> <span class="sy0">+</span> encodeURIComponent<span class="br0">&#40;</span>window.<span class="me1">AUTH_TOKEN</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>This will extend the parameters of any ajax request with the authenticity token. I hope this short guide gives you a better idea how to do REST in an unobtrusive way.</p>
]]></content:encoded>
			<wfw:commentRss>http://jetpackweb.com/blog/2009/09/09/unobtrusive-restful-jquery/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>jQuery Sortables: Getting DOM element position for an efficient ajax update in Rails</title>
		<link>http://jetpackweb.com/blog/2009/09/02/jquery-sortables-getting-element-position-for-an-efficient-ajax-update-in-rails/</link>
		<comments>http://jetpackweb.com/blog/2009/09/02/jquery-sortables-getting-element-position-for-an-efficient-ajax-update-in-rails/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 02:23:47 +0000</pubDate>
		<dc:creator>Brian Racer</dc:creator>
				<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[act_as_list]]></category>
		<category><![CDATA[haml]]></category>

		<guid isPermaLink="false">http://jetpackweb.com/blog/?p=308</guid>
		<description><![CDATA[The jQuery UI library has some excellent interaction functionality, especially &#8216;sortables&#8217; to make cool things like rearrangeable lists. Although there are lots of tutorials on sortable lists, one problem I have with them is the amount of database queries a single update can generate. They generally make use of the Sortable.serialize method, send *all* the [...]]]></description>
			<content:encoded><![CDATA[<p>The jQuery UI library has some excellent interaction functionality, especially &#8216;sortables&#8217; to make cool things like rearrangeable lists. Although there are lots of tutorials on sortable lists, one problem I have with them is the amount of database queries a single update can generate. They generally make use of the <a href="http://jqueryui.com/demos/sortable/#method-serialize" target="_blank">Sortable.serialize</a> method, send *all* the elements back to the server, and update each element with something like ActiveRecord&#8217;s <a href="http://apidock.com/rails/ActiveRecord/Base/update_all/class" target="_blank">update_all</a>(which can be smart), or worse, separate SQL queries for each list element.</p>
<p>What we can do instead is just send the id and position of the single element that has moved, and use <b>acts_as_list</b> to adjust the positions in the database. Lets say we have an <i>unordered list</i> of Video models <i>(I am using <a href="http://haml-lang.com" target="_blank">HAML</a> in this example)</i>:</p>

<div class="wp_syntax"><div class="code"><pre class="haml">%h3= &quot;Videos&quot;
%ul(class=&quot;sortable&quot;)
  - @videos.each do |video|
    %li{ :id =&gt; &quot;video_#{video.id}&quot; }= video.title</pre></div></div>

<p>That might output something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="html">&lt;h3&gt;Videos&lt;/h3&gt;
&lt;ul class='sortable'&gt;
  &lt;li id='video_5'&gt;Batman Begins&lt;/li&gt;
  &lt;li id='video_6'&gt;Ghostbusters&lt;/li&gt;
  &lt;li id='video_7'&gt;Indiana Jones and the Temple of Doom&lt;/li&gt;
 &lt;/ul&gt;</pre></div></div>

<p>We have the video&#8217;s database id&#8217;s in each of the element id&#8217;s, and we have given the <b>ul</b> element the <i>sortable</i> class so we can select it later. Now lets select that <b>ul</b> element and make it &#8216;sortable&#8217;:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript">$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $<span class="br0">&#40;</span><span class="st0">'.sortable'</span><span class="br0">&#41;</span>.<span class="me1">sortable</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>With that we can now drag each list item around. Now comes the important part. When we finish dragging a single list element we will send a single ajax request to the server that contains the numeric value of the element&#8217;s id, and it&#8217;s position in the list:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript">  $<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    $<span class="br0">&#40;</span><span class="st0">'.sortable'</span><span class="br0">&#41;</span>.<span class="me1">sortable</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
      <span class="kw3">stop</span><span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        $<span class="br0">&#40;</span>ui.<span class="kw1">item</span><span class="br0">&#41;</span>.<span class="me1">effect</span><span class="br0">&#40;</span><span class="st0">&quot;highlight&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="kw2">var</span> video_id <span class="sy0">=</span> $<span class="br0">&#40;</span>ui.<span class="kw1">item</span><span class="br0">&#41;</span>.<span class="me1">attr</span><span class="br0">&#40;</span><span class="st0">'id'</span><span class="br0">&#41;</span>.<span class="me1">replace</span><span class="br0">&#40;</span><span class="co2">/[^\d]+/g</span><span class="sy0">,</span> <span class="st0">''</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
        <span class="kw2">var</span> position <span class="sy0">=</span> ui.<span class="kw1">item</span>.<span class="me1">prevAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">length</span><span class="sy0">;</span>
        $.<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">'/videos/update_position'</span><span class="sy0">,</span> <span class="br0">&#123;</span>
          <span class="st0">'video_id'</span><span class="sy0">:</span> video_id<span class="sy0">,</span>
          <span class="st0">'position'</span><span class="sy0">:</span> position
         <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
         $<span class="br0">&#40;</span>ui.<span class="kw1">item</span><span class="br0">&#41;</span>.<span class="me1">effect</span><span class="br0">&#40;</span><span class="st0">&quot;highlight&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span></pre></div></div>

<p>Couple of notes:</p>
<p><b>ui.item</b> is the DOM element we are dragging</p>
<p><b>$(ui.item).attr(&#8216;id&#8217;).replace(/[^\d+]+/g, &#8221;))</b> is pulling out the list item&#8217;s DOM id and removing anything that isn&#8217;t numeric, so we are left with the model&#8217;s ID</p>
<p><b>ui.item.prevAll().length</b> is what gives us the list item&#8217;s position in relation to it&#8217;s parent <b>ul</b></p>
<p>Now our controller action can be as simple as:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby">Video.<span class="me1">find</span><span class="br0">&#40;</span>params<span class="br0">&#91;</span><span class="re3">:video_id</span><span class="br0">&#93;</span><span class="br0">&#41;</span>.<span class="me1">insert_at</span><span class="br0">&#40;</span>params<span class="br0">&#91;</span><span class="re3">:position</span><span class="br0">&#93;</span><span class="br0">&#41;</span></pre></div></div>

<p>Again this requires <b>acts_as_list</b>.  I believe this should never do more that 4 queries: One to find the model, one to update it&#8217;s position, and possibly two more to shift what was above and below it previously. Hopefully this saves you some SQL queries on larger lists.</p>
]]></content:encoded>
			<wfw:commentRss>http://jetpackweb.com/blog/2009/09/02/jquery-sortables-getting-element-position-for-an-efficient-ajax-update-in-rails/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Install Phusion Passenger (a.k.a. mod_rails) on cPanel Server</title>
		<link>http://jetpackweb.com/blog/2009/07/21/install-phusion-passenger-a-k-a-mod_rails-on-cpanel-server/</link>
		<comments>http://jetpackweb.com/blog/2009/07/21/install-phusion-passenger-a-k-a-mod_rails-on-cpanel-server/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 18:06:56 +0000</pubDate>
		<dc:creator>Brian Racer</dc:creator>
				<category><![CDATA[cpanel]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[passenger]]></category>

		<guid isPermaLink="false">http://jetpackweb.com/blog/?p=129</guid>
		<description><![CDATA[Although cPanel has built in support for running Ruby or Rails apps, it uses Mongrel as the server and doesn&#8217;t allow more than one instance per user. That makes it pretty useless for any application that gets even a moderate amount of traffic. Instead we can install]]></description>
			<content:encoded><![CDATA[<p>Although cPanel has built in support for running Ruby or Rails apps, it uses <a href="http://mongrel.rubyforge.org/" target="_blank">Mongrel</a> as the server and doesn&#8217;t allow more than one instance per user. That makes it pretty useless for any application that gets even a moderate amount of traffic. Instead we can install <a href="http://www.modrails.com/" target=_blank" />Phusion Passenger</a> (a.k.a mod_rails), which in my opinion is a much nicer solution anyway.</p>
<p>First we need to make sure Ruby is installed via a cpanel script:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">sudo</span> <span class="sy0">/</span>script<span class="sy0">/</span>installruby</pre></div></div>

<p>Now we can install the passenger gem:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">sudo</span> gem <span class="kw2">install</span> passenger</pre></div></div>

<p>Next, compile the apache2 module</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">sudo</span> passenger-install-apache2-module</pre></div></div>

<p>The installer may tell you that the the Apache development headers are needed and will suggest &#8216;yum install httpd-devel&#8217;. Since cPanel compiles it&#8217;s own version of apache, yum is configured to ignore that package. That is OK, because the program we need is already installed, we just have to tell Passenger where to find it.</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="re2">APXS2</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>apache<span class="sy0">/</span>bin<span class="sy0">/</span>apxs <span class="re2">PATH</span>=<span class="re1">$PATH</span>:<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>apache<span class="sy0">/</span>bin passenger-install-apache2-module</pre></div></div>

<p>Everything should go OK this time, and the installer will give you a few lines to add to your apache config file. It&#8217;s best practice with cPanel not to put these in your main httpd.conf, but rather the pre_main_global.conf:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">vi</span> <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>apache<span class="sy0">/</span>conf<span class="sy0">/</span>includes<span class="sy0">/</span>pre_main_global.conf
&nbsp;
LoadModule passenger_module <span class="sy0">/</span>usr<span class="sy0">/</span>lib<span class="sy0">/</span>ruby<span class="sy0">/</span>gems<span class="sy0">/</span><span class="nu0">1.8</span><span class="sy0">/</span>gems<span class="sy0">/</span>passenger-X.X.X<span class="sy0">/</span>ext<span class="sy0">/</span>apache2<span class="sy0">/</span>mod_passenger.so
PassengerRoot <span class="sy0">/</span>usr<span class="sy0">/</span>lib<span class="sy0">/</span>ruby<span class="sy0">/</span>gems<span class="sy0">/</span><span class="nu0">1.8</span><span class="sy0">/</span>gems<span class="sy0">/</span>passenger-X.X.X
PassengerRuby <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ruby</pre></div></div>

<p>Now we need to setup passenger to run on a per virtual host basis. Open up the httpd.conf file and find the virtual host you want to run a Rails app and add this line:</p>

<div class="wp_syntax"><div class="code"><pre class="bash">Include <span class="st0">&quot;/usr/local/apache/conf/userdata/std/2/username/domain_name/*.conf&quot;</span></pre></div></div>

<p>Replace <i>username</i> with the username of the account.</p>
<p>Now we need to create the directory we just specified, and also create a configuration file letting passenger know it should load for this host:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">mkdir</span> <span class="re5">-p</span> <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>apache<span class="sy0">/</span>conf<span class="sy0">/</span>userdata<span class="sy0">/</span>std<span class="sy0">/</span><span class="nu0">2</span><span class="sy0">/</span>username<span class="sy0">/</span>domain_name<span class="sy0">/</span>
<span class="kw2">vi</span> <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>apache<span class="sy0">/</span>conf<span class="sy0">/</span>userdata<span class="sy0">/</span>std<span class="sy0">/</span><span class="nu0">2</span><span class="sy0">/</span>username<span class="sy0">/</span>domain_name<span class="sy0">/</span>rails.conf
&nbsp;
RailsBaseURI <span class="sy0">/</span></pre></div></div>

<p>To make sure those files load, run this:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="sy0">/</span>scripts<span class="sy0">/</span>ensure_vhost_includes <span class="re5">--user</span>=username</pre></div></div>

<p>We need to make sure cPanel records the changes we have for when it rebuilds those files, so run the following two commands:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>cpanel<span class="sy0">/</span>bin<span class="sy0">/</span>apache_conf_distiller <span class="re5">--update</span>
<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>cpanel<span class="sy0">/</span>bin<span class="sy0">/</span>build_apache_conf</pre></div></div>

<p>We can now restart apache:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>httpd restart</pre></div></div>

<p>Since by default the Apache Document Root for each host is /home/username/public_html, you will probably need to symlink that to your applications public directory:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">ln</span> <span class="re5">-s</span> <span class="sy0">/</span>home<span class="sy0">/</span>username<span class="sy0">/</span>railsapp<span class="sy0">/</span>public <span class="sy0">/</span>home<span class="sy0">/</span>username<span class="sy0">/</span>public_html</pre></div></div>

<p>To restart that application, you just need to touch the restart.txt file:</p>

<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">touch</span> <span class="sy0">/</span>home<span class="sy0">/</span>username<span class="sy0">/</span>railsapp<span class="sy0">/</span>tmp<span class="sy0">/</span>restart.txt</pre></div></div>

<p>And there you have it, a working high performance rail application server on cPanel! For more information on tuning the Passenger configuration, read the <a href="http://www.modrails.com/documentation/Users%20guide%20Apache.html" target="_blank">complete docs</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jetpackweb.com/blog/2009/07/21/install-phusion-passenger-a-k-a-mod_rails-on-cpanel-server/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

