Learning Ruby on Rails Day 40

Where did time go? Last time I added an entry to my Learning Ruby on Rails journal, it was May 6th. Today is October 30th. There may have been 40 days of learning between then and now. I am back into it — is what matters. Teaching myself Ruby on Rails has become a sort of yoga practice in my life. It feels mostly good and places a nice comfy shield between all the bad noise in my life and my easily-troubled head.

I have set each chapter of a book I have yet to finish reading as 'action' in my Action Method. The book is Simply Rails 2. I am plowing along. The grass is green and cut short and clean. Patrick Lenz is a fantastic writer. Thanks to him, the pasture smells great. Actually, I smelled something funny tonight. I got back into wrapping my head around RJS templates.

They are written in Ruby. Like *.html.erb templates, they are stored in the views folder. They have the extension .js.rjs because once the Rails engine is done with them JavaScript is returned to the browser. Ah, I am not explaining well. Good definition found in Foundation Rails 2: “RJS is Rails’s solution for generating JavaScript code using Ruby. [It] is a server-side solution for generating dynamic responses to AJAX requests without having to resort to writing [...] JavaScript. [...] RJS code [...] resides in specially named RJS templates that can be found in the same directories as our traditional HTML views. However, whereas our standard view template would be named something like index.html.erb, the RJS template for the same action would be named index.js.rjs. So you can see it [follows] the same naming convention with the first word [being] the action it’s associated to, the second [word] representing the type of content that we’re returning (js for JavaScript in this instance), and the final [word] representing the rendering engine that is used to parse the template (RJS for this).”

I usually install the vendor plugin jRails to get rid of Prototype and script.aculo.us when I build any new application. There exists a jRails gem now, but I didn't have much success with it.

jRails, FYI, has moved to github. “ennerchi” and “aaronchi” are the same guy. To install jRails:
ruby script/plugin install git://github.com/aaronchi/jrails.git

Not sure whose fault it is, probably that of jRails, but I'm sending the authenticity_token twice with every Ajax request.


I am using the form_remote_tag helper:

<% form_remote_tag :url => story_votes_path(@story) do %>
  <p><%= submit_tag 'Shove This' %></p>
<% end %>

The following HTML is generated:

<form action="/stories/5-google/votes" method="post" 
onsubmit="jQuery.ajax({ data:jQuery.param(jQuery(this).serializeArray()) +
'&amp;authenticity_token=' + encodeURIComponent('zctxjCg1I5w9LTgk7YvvSEsvAFN4Km+FzvsJuU2Jrok='),
dataType:'script', type:'post', url:'/stories/5-google/votes'}); return false;">
  <div style="margin:0;padding:0">
    <input name="authenticity_token" type="hidden"
 value="zctxjCg1I5w9LTgk7YvvSEsvAFN4Km+FzvsJuU2Jrok=" /></div>
  <p><input name="commit" type="submit" value="Shove This" /></p></form>

The form already contains a hidden input field that stores the authenticity token (this protects against forgery). jQuery serializes the form, hence serializes that token, but then... it adds it again! That's not right.

data: jQuery.param(jQuery(this).serializeArray()) + '&amp;authenticity_token=' +
encodeURIComponent('zctxjCg1I5w9LTgk7YvvSEsvAFN4Km+FzvsJuU2Jrok='), ...

The following code should suffice:

data: jQuery.param(jQuery(this).serializeArray()), ....


Also, RJS requires some getting used to for me. Seems weird to have an Ajax request return JavaScript to execute, rather than JSON, or text data, or XML, or nothing. I usually use callback functions when doing Ajax: when the data is returned, if any, some JavaScript function is run, doing whatever to the page. There's really different shit happening here, although results are the same of course.

text/javascript; charset=utf-8

The JavaScript returned to the browser is a big Try and Catch. If a JavaScript error occurs, an alert box tells you what went wrong.

try {
jQuery("#vote-score").html("Score: 112");
} catch (e) { alert('RJS error:\n\n' + e.toString());
alert('jQuery(\"#vote-score\").html(\"Score: 112\");
\njQuery(\"#vote-score\").effect(\'highlight\',{},2000);'); throw e }

Eh, this looks a bit convoluted:


Couldn't we just use this — not sure:


Unobtrusive jQuery

I prefer unobtrusive jQuery just because it's more manageable. I also like to write my own JavaScript — or at least be able to edit it. Ryan Bates shows here how to use jQuery without jRails. No helper functions. No JavaScript generated for you. Ryan Bates uses Ajax requests that return JavaScript as does jRails. But the JavaScript that's returned is stored, this time, in a .js.erb template.

The form on the page is submitted asynchronously thanks to some jQuery added to application.js. (Shown below.) Ryan Bates uses a simple jQuery.post call. And he does uses jQuery(this).serialize! I may try to modify my Shovell app (the book project in Simply Rails 2) to use a .js.erb template. What we're comfortable with may not be the better way, though. If I get used to using RJS templates, I may learn to love them. Not sure.

How to use jQuery with Rails - Screencast by Ryan Bates