Dear Railsists, Please Don’t be Obtrusive

obtrusive_or_not.png
Update: thanks to Jon Wood aka jellybob, a prototype demonstration has been added, which is even better than my original jQuery btw as it degrades gracefully. Check it out in the ‘prototype-unobtrusive’ directory.

I am guessing 9 out of 10 of you reading the title is prepared for yet-another Rails drama on some obtrusive community members, and because everyone is tired of Rails dramas, I am risking that some of you won’t care to read the article – but I couldn’t resist :-) . Actually I’d like to talk about usage of (un)obtrusive Javascript – why is it a bad idea to be obtrusive, especially given that (as you will learn from the article) writing unobtrusive Javascript is not harder, and you get the warm, fuzzy feeling of writing nice and clean code!

The Drill

To demonstrate the differences, I’ll lead you through the creation of a quick AJAXy shout wall both the default/standard (and obtrusive) way, then do the same with unobtrusive Javascript to show you that contrary to the popular belief, you don’t need to memorize the “Tome of Javascript Black Magick Tricks” by heart, use obscure libraries or special coding techniques to achieve clean, unobtrusive code. The shout wall is simply a form for posting a new message, and a list of messages below it, like so:



shout_wall.png



(You can check out the code used in this post from it’s github repository).

The Standard Way

Note: If you’d like to follow along, please use the provided pastie links – do not try to cut & paste multiple lines from the page (single lines are OK), as it will be b0rk3d.

  1. Creating a new Rails application

    rails obtrusive-shout-wall
      
  2. Get into the Rails dir

    cd obtrusive-shout-wall
      
  3. Generate the resource message

      
    script/generate resource message
      
  4. Add this the following to the generated migration (some_timestamp_create_messages (Get it from pastie):

    t.string :author
    t.text :message	
    
  5. Run the migrations:

    rake db:migrate
    
  6. Because we want to view the messages in reverse order (newest one first), we add a default scope to the Message model (in message.rb):

        default_scope :o rder => 'created_at DESC'
    
  7. Create the application layout – create a new file in app/views/layouts called application.html.erb, and fill it with the following content (Get it from pastie):

    
      
        <%= stylesheet_link_tag "application" %>
    		<%= javascript_include_tag :defaults %>		
      
    	
        <%= yield %>
    	
    
    
  8. Create a file application.css and drop it into public/stylesheets. Add the following content (Get it from pastie):

    body {
    	background-color:#FFFFFF;
    	color:#333333;
    	font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;
    	margin:0 auto;
    	padding:0;
    	text-align:center;
    	width:960px;
    }
    
    #messages {
    	text-align: left;
    	margin-left: 80px;
    	margin-top: 50px;
    }
    
    #message-form {
    	text-align: left;
    }
    
    #message-form dl {
    	margin:10px 0 0 80px;
    }
    
    #message-form dd {
    color:#666666;
    font-size:11px;
    line-height:24px;
    margin:0 0 5px 80px;
    }
    
    #message-form dt {
    	float:left;
    	font-size:14px;
    	line-height:24px;
    	width:80px;
      text-align: left;	
    }
    
    #author {
      margin-right: 640px;
    }
    
    #message {
      width: 600px;
    	height: 200px;
      margin-right: 194px;
    }
    
    .message {
      margin-bottom: 20px;
    }
    
    .first_row {
      padding-bottom: 10px;
    }
    
    .message-meta {
    	font-size: 12px;
    }
    
    .author {
      color: #FF5050;
    	font-weight: bold;
    }
    
    .new-message-label {
      text-align: left;
      padding-top: 30px;
      margin-left: 80px;
    }
    
    #submit-button {
      float : right;
      margin-right: 195px;
      margin-top: 10px;
    }
    
  9. Create a new action, index in MessagesController (Get it from pastie):

    def index
      @messages = Message.all    
    end
    
  10. This goes into app/views/messages/index.html.erb (Get it from pastie):

    Enter new message!

    <% remote_form_for :message, :html => {:id => "message-form"} do |form| %>
    Author:
    <%= text_field_tag 'author' %>
    Message:
    <%= text_area_tag 'message' %>
    <%= submit_tag "Submit!", :id => "submit-button"%> <% end %>
    <%= render :partial => 'message', :collection => @messages %>

    We are showing the form for the messages and list the already exiting messages below the list.
    Note that we are using the _remote_form_for_ Rails helper to create an AJAXy form. This is already obtrusive, since if you observe the generated HTML, you will see that the form has an onsubmit parameter with some horribly looking code attached to it.:



    Obtrusive helper.png



    Sure, you can go ‘meh’ all the way, but slinging Javascript code all over the place is just as bad idea as writing inline CSS (or even worse, using HTML code for styling) or putting Rails code into views. It will work without any problems – but it’s just not the right way of doing things, especially if your code is going to hit a certain size.
  11. You probably noticed that we are rendering a message as a partial – so create a partial file app/views/messages/_message.html.erb with the following content (Get it from pastie):

    on <%= message.created_at.to_formatted_s(:long_ordinal) %>, <%= message.author %> said:
    <%= message.message %>
  12. We need a ‘create’ action in MessagesController in order to process the form submission (Get it from pastie):

    def create
      @message = Message.create(:author => params[:author], :message => params[:message])
    end
    
  13. And obviously we’ll need to render something to respond to the create action. Using the standard Rails way, RJS, we might come up with something like this (in app/views/messages/create.js.rjs – Get it from pastie):

    page.insert_html :top, "messages", :partial => 'message', :o bject => @message
    page.visual_effect  :highlight, "message-#{@message.id}"
    

    Here we insert the “messages” partial, using the just created @message, and throw a splash of yellow fade into the mix for good measure. Easy peasy.

  14. We are done! Fire up script/server, hit localhost:3000/messages and voila!

The Good Way

Here I am presenting only the steps that are different from the above – i.e. if step 3 is skipped, use the one from above.

  1. Creating a new Rails application

      rails unobtrusive-shout-wall
      
  2. Get into the Rails dir

    cd unobtrusive-shout-wall
      
  3. Same as above
  4. Same as above
  5. Same as above
  6. Same as above
  7. Since we are going to use jQuery (unobtrusiveness is *not* a property of jQuery, you can be just as unobtrusive with Prorotype – but I switched to jQuery just before learning how, and now I am lazy to go back check out how in the ‘prototype unobtrusive’ directory in the github repository), you have to download jQuery with some basic effects, as well as an AJAX form handling library (still from the directory unobtrusive-shout-wall – Get it from pastie):
  8. curl http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js > public/javascripts/jquery.js
    curl http://www.malsup.com/jquery/form/jquery.form.js?2.28 > public/javascripts/jquery-form.js
    curl http://view.jquery.com/tags/ui/latest/ui/effects.core.js > public/javascripts/effects.core.js
    curl http://view.jquery.com/tags/ui/latest/ui/effects.highlight.js > public/javascripts/effects.highlight.js
    

    and replace

    <%= javascript_include_tag :defaults %>
    

    with

    <%= javascript_include_tag 'jquery' %>		
    <%= javascript_include_tag 'jquery-form' %>
    <%= javascript_include_tag 'application' %>
    <%= javascript_include_tag 'effects.core' %>
    <%= javascript_include_tag 'effects.highlight' %>		
    

    in the layout file.

  9. Same as above
  10. Same as above
  11. Same as above – just delete “remote” from the name of the helper, i.e. use a standard Rails view helper, form_for
  12. Same as above
  13. Since we are not relying on Rails to do the rendering for as via a template file, we return the html chunk that we will render from Javascipt. So your create action should look like (Get it from pastie):
    def create
      @message = Message.create(:author => params[:author], :message => params[:message])
      render :partial => 'message', :o bject => @message
    end
    
  14. Now comes the fundamentally different part – instead of using RJS to respond to the create action, we move all our code to application.js (Get if from pastie):
    $(document).ready(function() {      
      $("#message-form").ajaxForm({success: handleNewMessage});
    
      function handleNewMessage(response, statusText) {
        $("#messages").prepend(response).effect("highlight", {}, 1500);
      }    
    });
    

    I don’t think so that this code is particularly more complicated or hard to understand that the RJS one. Everything is inside the ready() function, which means that it’s only run once the document is properly loaded. Then we declare that “#message-form” is an AJAX form, and that upon successful submission, the handleNewMessage() method should be called. And if that happens, we add the response (which is the return value of the “create” action) to the “#messages” div, just as we did in RJS. Then we apply the yellow fade! w00t!

  15. Same as above

(You can check out the code used in this post from it’s github repository).

Conclusion

As you can see, the only real difference between the obtrusive and non-obtrusive version is in the last 2 points (downloading and including the jQuery header files can be easily solved with Rails templates): instead of leaving the rendering part to Rails, we return the response as a string and dynamically insert it from jQuery. With about the same effort, we kept all the Javascript code in application.js, which is much cleaner this way (you can open up 1 file and check out all the JS/AJAX behavior in one place), especially after introducing a lot of Javascript functionality into your code – in other words, for the same amount of work we got something much better. Please try to keep this in mind when you are working with Javascript and Rails the next time – believe me, it can save you from a lot of pain!

65 thoughts on “Dear Railsists, Please Don’t be Obtrusive

  1. Pedro Martínez se inició en esto del SEARCH ENGINE MARKETING tras llevar 7 años programando, de la forma
    más práctica: aceptando el reto de un cliente.

  2. Minka Kelly snags designer boots for fall at Marshalls in Los
    Angeles Lakers superstar Kobe Bryant transformed his body
    ached, and you just got our campervan hire auckland sauce cookijg still.
    This is Kiefer with DangerouslyHardcore. Just after
    studying opinions of many oof tnese popular diets campervan hire auckland today.

    So some of which that encode for all your carbs way back down. I did just a matter of your choice is square ceramic
    campervan hire auckland dishes with dull surface finish.

  3. Brain Age group: Train Your mind iin A few minutes a Day featured several brief games that designer Doctor Ryuta Kawashima claimed might increase blood flow to the prefontal cortex.

    Whilst they produce a dinner feast for their dolols annd stufed
    animals, you will definitely get hours associated with enjoyment viewing
    them figure out how to be creative. The other issue is
    that We’ve wasted about 4 hours in past times week actively playing
    this.
    It is a page to organize the video games I’ve developed or revised significantly which includes notes about content.
    The home in Eliminated Home” is detinitely filled with nods to the
    sfyle of video games that inspired it; a single subtopic questioned students to collect the hidden references.
    There aree plenty of different video games
    that can be effetive when used by the right instructor for the correct group of students, ” Husøy explained.
    After i look foor ganes to put in the classroom, I use the same technique as any various other media.
    They are destroying the common values and lexikcon that allow alll of us to get in touch with each other
    plus hold all of us together as a society.
    The majority of games with a sexual concept feature a man character and a lot of naked women.
    A neew number of games appear regularly and therefore you do not obtain bored actifely playing the same video games
    again and again, tjey get a brand new variegy
    of onlinme game every time they go online. Thee newest series of vide games these day’s aare get away games to have to come
    ouut off the capture solve the puzzle, discover the
    keys and score a lot more ass possible. Take notiuce though,
    since the game increases as you go. If you like Code Lyoko games you will discover others on mygames4girls.

    This is a page to organize the games We’ve creasted orr modified significantly with some information about articles.
    Thhe house within Gone Home” is full of nods tto the genre associated
    with games tat will inspired this; one subtopic challenged college
    students to collect the particular hidden referrals.

    There are plenty of different games that can be effective
    when used by the best teacher for that right number of
    students, ” Husøy described. When I look for games to put inn the class room,
    I usse exactly the sawme approach as any other
    press. They aare wiping out the common ideals and lexicon tgat permit us too communicate with one another and hold us
    together as a culture. The majority of video games with a
    sexual theme have a male character and lots of naked women.
    The particular legacy stiill left by Russia’s first winter Games is one of
    glistening purpose-built arenas with little if any post-Games make use of, a massive
    overhaul of facilities at the Dark sea holiday resort and a record price
    tag that will triggered changes for future Olympics.
    Simply by blaming the particular European criusis on income and thee price of labor plus ignoring the
    role of redit runs within the financial union, economists
    are letting Big Banks off the catch, absolving all of them from any kind of
    responsibility, leafe alone fault – and unjustifiably so.

  4. I used to be recommended this web site by means of
    my cousin. I’m not sure whether this put up is written by way of him as
    no one else recognise such distinct approximately
    my difficulty. You are amazing! Thanks!

  5. Boys played video classic pc games download free (Siobhan) with these features, such as Psychic Detective,
    Resident Evil, Condemned Criminal Origins, and CS7: Three Dimensions of Murder, but unlike the girls, did not cross
    gender lines in their choices. These all make for good activity on rainy or dark days.

    If you purchase a new game and do not like it, you have wasted a lot of money.

  6. Resimin ve sanat?n ferahlat?c? etkisi ile sanat eserlerindeki hisleri yakalayabilmek hiç ?üphe yokki e?siz bir tat ve ayr?cal?k kazand?r?r bizlere. Sanat eserleri üretmek ve hislerinizi kar??dakine aktarabilece?iniz bir his kazand?rmak sizin fark?n?z? ortaya koyacakt?r.
    Resim kursu olarak sizlere gerekli e?itimleri vererek ki?isel geli?iminizi tamamlayarak sizi sanat eserleri üretebilecek bir k?va?a getirerek sanat eserleri ile ölümsüzle?tirmek istiyoruz. Sizde sanat eserleri üretmek için bizi seçebilirsiniz.

  7. Thanks for any other informative web site. Where else could I am getting that type of information written in such an ideal manner?
    I have a venture that I’m just now running on, and I have been on the glance out for such info.

  8. Türkiyenin bir numaral? e?itim kurumu olan bahçe?ehir bale kursu ile gelece?inizi yönlendirebilirsiniz. Rüya avc?s? sanat merkezi ile sektörde 28 y?ll?k deneyimimiz ile e?itimlerimize bak?rköy resim kursu ile beraber ?imdide bahçe?ehir bale kursu ad? alt?nda e?itim vermekteyiz.

    Avc?larda bulunan e?itim kurumumuz ile Bahçe?ehir’de bulunan kurumumuzun ?stanbulun özellikle Avrupa yakas?ndaki bir çok ö?renciye olanak sa?lamaktad?r.

    http://ruyaavcisi.com/bahcesehir-bale-kursu/

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>