Thursday, June 9, 2011

Working with Jquery in Rails

Still working on Chorenivore. After getting some help from Matt and David, I'm using some jquery for handling flash :notice messages. At first, I just wanted to make it so the :notice would fade away after a few seconds.

I initially tried this with some Prototype code David showed me, but couldn't get it to work for one reason or another. After a bit more digging (and prodding from both David and Matt) I decided I should just switch over to Jquery. Everything I've read says it's got a much wider development base than Prototype, and Rails 3.1 will be using it as the default javascript library, anyway. Might as well get used to it now!

Switching to Jquery from Prototype proved a bit tricky. Good thing I don't have tons and tons of code that had to be converted, huh? Here's a page I found that helped me:

Switching from Prototype to Jquery

Easy enough! This didn't take long to find (third page on a google search, but that's an eternity by today's standards) so I'm hoping it might help others out.

Anyway, back to Chorenivore! Here's the Jquery script Matt showed me that I modified and ended up using:

setTimeout(function() {
$('#flash_notice').fadeOut('slow');}, 800

I'm not super familiar with Javascript, but a couple of things made sense. 'slow' refers to how quickly the message fades away, and 800 refers to how long it stays on the screen. '#flash_notice' refers to every flash[:notice] and this could just as easily be applied to flash[:error] or flash[:alert]. It's funny how becoming familiar with one coding language makes others easier to read and manipulate.

After I got this script running, I decided I didn't want my flash:notice running across the top of the application. I pulled that code out of application.html.erb, threw it into index.html.erb, slapped a div on it and called it macaroni! Problem solved. It feels AWESOME to mark things off the functionality and features checklist I made for Chorenivore.

Now, how about a couple of questions? You ready?

Here's the code I've got for updating whether a task is finished or not.

<%= form_for(task) do |f| %>
  <%= f.hidden_field :finished, :value => !task.finished %>
  <div class="actions">
    <% if task.finished %>
      <%= image_submit_tag 'finished.png' %>
    <% else %>
      <%= image_submit_tag 'unfinished.png' %>
  <% end %>

Is there a way to pass multiple values to a hidden_field? Right now, I can define a task as finished, but there's no definition for being unfinished. It's just displaying the unfinished button if a task is not marked as finished. I'd like to do this so I can define custom flash :notice messages for when a task is marked as finished from unfinished and vice versa.

I had lunch with Eli today and it's always great to talk to programmers about programming. I find the fact that I've signed up for a never ending stream of headaches, frustrations and triumphs oddly comforting. This is that coding crack I've heard so much about, right?


  1. in TasksController#update

    task_status = @task.finished? ? 'finished' : 'not finished'
    redirect_to(tasks_path, :notice => "Task was marked as #{task_status}.")

    Or better yet, make it an attribute on the model:

    class Task < ActiveRecord::Base
    def status
    finished? ? 'finished' : 'not finished'

    redirect_to(tasks_path, :notice => "Task was marked as #{@task.status}.")

    I don't know why you'd move the flash messages stuff out of the layout though. You'll have to re-add it to any page you want it to be visible on.

    I'm glad you are getting it though!

  2. jQuery has a matching syntax that patterns itself after CSS to make it more intuitive. $('#flash_notice') matches elements on the page with an id="flash_notice".

    You should probably keep the actual flash message display code in the application layout, as this layout wraps every view across the site. Moving it to index.html.erb means that it will only be displayed when hitting that view. The 'yield' in application layout is where the view code gets inserted, so if you want it at the bottom of the page, just move it to below the 'yield'.

  3. Yeah, makes sense. My initial reasoning for moving the div containing the flash :notice is users will only be looking at the index.html.erb page, but that could change in the future. There's no compelling argument for moving it out of the layout, so back in it goes!

    @David thanks for the input. I was wondering how to do this. Making it an attribute is just what I was looking for!

    @Matt Yeah, I initially thought Prototype was easier to read, but Jquery feels much more intuitive now. Plus I won't be coding my own javascript for a while yet but rather using and modifying code others have produced.

  4. jQuery seems very straightforward for most of the things that I do. That being said, I hear Prototype is badass and really what you want to go for if building JavaScript applications.