Chronicling the trials and tribulations of developing for the modern web.



Parsing Parameters with Javascript

Posted by Pat Nakajima on November 19, 2007 in Programming.
Update: While this post is nice, a much better way to parse parameters is to use Prototype’s (if you’re using Prototype that is) built-in String#toQueryParams() method. To quote the official documentation, this method “Parses a URI-like query string and returns an object composed of parameter/value pairs.” Live and learn.

Wish you had a params object to use in your Javascript, just like the one you get in your Rails controllers? Well wish no longer. Just add the following script to your application code:
params = { };
document.URL.split('?')[1].split('&').each(function(par) {
  params[par.split('=')[0]] = par.split('=')[1];
})

Then when you’re on a page with a URL like “http://your-site.com/users?name=pat”, you can access the value of the name parameter like so: params['name'].

The biggest limitation of this script is that it’s limited to GET params, in other words, the ones found in the URL. Still, it’s a clean and easy way to get a Rails-like syntax in your Javascript.

The Trouble with RSpec

Posted by Pat Nakajima on November 02, 2007 in Programming.

These days, most developers (thankfully) recognize the value of test driven development. Still, the question, “To test, or not to test…” lives on, with some developers preferring to “spec” instead. Spec driven development (or Behavior Driven Development) in Ruby or Ruby on Rails means using the RSpec framework to describe what the code ought to do in a syntax that reads very much like plain English. And that’s the problem.

While English is a great language for communicating with other humans, it’s far too low level to be useful as a language to poke and prod Ruby code. While computer languages were originally designed as a way for humans to communicate with machines, they’re now (at least the good ones) frameworks upon which we are able to structure our thought processes. We have the problem solving muscle. We just need the programming language hammer.

And so I believe that Ruby is the best language for testing Ruby code. And in the same way I wouldn’t write a one-act play in a programming language, I don’t believe it’s productive to expect an interpersonal language to assume the responsibilities and abilities of programmatic one.

The Perils of Test-Driven Development

Posted by Pat Nakajima on July 08, 2007 in Programming.

When I first started devin’ that web, it took me a bit of time to really wrap my mind around the concept of modeling data. Once I started to really learn the process, it became somewhat addicting. I got the urge to model everything in my life, from my girlfriend (she was less than enthused) to my drum set. I was finally able to scale it back to times when modeling is actually appropriate, but for a little while, things were a bit absurd.

Now I’m discovering similar problems caused by my newfound love for TDD. For those of you not in the know, TDD is a practice in which one writes a test for any code he/she wishes to implement before that code is even written. Needless to say, the test fails the first time it’s run, at which point the developer write the implementation code required to make the test pass. In this way, each facet of the application has test code to back it up, giving the developer some assurance that refactoring something in one module won’t break something in another. Also, instead of writing a bit of code, then running to the browser to make sure that the code works, the developer can just make sure that the associated test passes. TDD helps you write more focused code, and cuts down on fixing mysterious bugs later in development by an order of magnitude.

So what’s my problem?

I now feel that I need to write tests for everything I do before I take action. Example: I woke up, groggy and in need of a visit to the bathroom. However, I felt that I couldn’t leave the bed until I wrote an integration test for going to the bathroom. Unaware of a testing framework for such problems, I eventually had to go force myself to go, and fortunately I haven’t seen any negative repercussions of my decision. Still, the fact that I had to think about it is pretty darn absurd, and so I thought I might share that with you.
def test_should_need_to_go_to_the_bathroom
  @pat = Pat.new
  @pat.bladder.full? = true
  assert @pat.need_to_tinkle?, "Wet pants." 
end

# From Test::Unit...
#    _
#   | |
#   | |
#  \   /
#   \_/
# 
# ...to rSpec

it "should need to pee" do
  @pat = Pat.new
  @pat.bladder.full? = true
  @pat.should need_to_tinkle?
end
Update: I’m looking into rSpec now. TDD is so last year. These days it’s all about BDD Hopefully I won’t feel the need to write a specification for the can, but time will tell. I’ll pass the word along to you.

Fun with refactoring footodo

Posted by Pat Nakajima on June 21, 2007 in Programming.

I just spent some time whipping footodo into shape for production. (When you’re just giving away the code, it’s a bit easier to forget about some things.) Thankfully, I have you, the ever-brilliant reader, to keep me honest. In that spirit, I’d like to share a couple of my favorite fixes with you.

From hideous to beautiful

If you took a look at the TodosController before today, you probably saw this offensive method, along with its comment of condemnation:


  # This code needs to be rewritten or destroyed. Couldn't the update method be used instead?
  def toggle_complete
    @todo = Todo.find(params[:id])
    if params[:complete]
      @todo.complete = false
      @todolist = @todo.todolist
      respond_to do |format|
        if @todo.save
          flash[:notice] = 'Todo was successfully updated.'
          format.js   { render :action => 'uncompleted' }
          format.html { redirect_to todo_url(@todo) }
          format.xml  { head :ok }
        else
          format.js   { render :action => 'error' }
          format.html { render :action => "edit" }
          format.xml  { render :xml => @todo.errors.to_xml }
        end
      end
    else
      @todo.complete = true
      @todolist = @todo.todolist
      respond_to do |format|
        if @todo.save
          flash[:notice] = 'Todo was successfully updated.'
          format.js   { render :action => 'completed' }
          format.html { redirect_to todo_url(@todo) }
          format.xml  { head :ok }
        else
          format.js   { render :action => 'error' }
          format.html { render :action => "edit" }
          format.xml  { render :xml => @todo.errors.to_xml }
        end
      end
    end
  end

Tsk tsk, the new version is DRY-er, and a heck of a lot more readable. Interestingly enough, it’s not a dramatic decrease in code. It is, however, a dramatic increase in flexibility. By making the conditional responses their own methods, I’ve pulled a little bit of strategy pattern action by encapsulating what varies in the method, while leaving the static parts intact.


  # Refactored the kilobytes out of this one. The complete attribute passed in
  # in the params is the former state of the @todo's complete attribute.
  def toggle_complete
    @todolist = @todo.todolist
    params[:complete] ? uncomplete! : complete!
    respond_to do |format|
      if @todo.save
        format.js   { render :action => @rjs }
        format.html { redirect_to todolist_url(@todo.todolist) }
        format.xml  { head :ok }
      else
        format.js   { render :action => 'error' }
        format.html { redirect_to todolist_url(@todo.todolist) }
        format.xml  { render :xml => @todo.errors.to_xml }
      end
    end
  end

  def complete!
    flash[:notice] = 'Todo was successfully completed.'
    @todo.complete = true
    @rjs = 'completed'
  end

  def uncomplete!
    flash[:notice] = 'Todo was successfully uncompleted.'
    @todo.complete = false
    @rjs = 'uncompleted'
  end

Lesson learned: Never trust your users

One of my oversights with this app was the fact that any User was able to access the :show action of the TodosController. An obvious problem in hindsight, but at the time, I thought the fact that I wasn’t linking to that action was enough to keep them private. (Again, I didn’t design this application with production in mind.) Once I was made aware of the problem by an eagle-eyed reader, I set to work fixing it.

Here’s how I’m keeping your to-dos private.


  # I plopped this before_filter directly after the :login_required filter.
  before_filter :ensure_ownership, :only => [:show, :edit, :update, :destroy, :toggle_complete]

  # The before_filter calls this method, which checks for a to-do item that corresponds
  # to the :id passed in the parameters. If it does, it calls the ensure_ownership method
  # that makes sure the current_user is authorized to view the item.
  def ensure_validity
    !Todo.find(:first, :conditions => { :id => params[:id] }).nil? ? ensure_ownership : redirect_to(todolists_path)
  end

  def ensure_ownership
    @todo = Todo.find params[:id]
    unless @todo.todolist.user === current_user
      flash[:notice] = "That doesn't belong to you!" 
      redirect_to todolists_path
    end
  end

  # And of course, I have tests.

  # This one goes out to Jamie (http://jamie.ideasasylum.com)
  def test_should_not_show_if_not_owner
    login_as('aaron')
    get :show, :id => 1
    assert_response :redirect
    assert_redirected_to todolists_path
  end

  def test_should_not_get_edit_if_not_owner
    login_as('aaron')
    get :edit, :id => 1
    assert_response :redirect
    assert_redirected_to todolists_path
  end

  def test_should_not_update_if_not_owner
    login_as('aaron')
    put :update, :id => 1
    assert_response :redirect
    assert_redirected_to todolists_path
  end

  def test_should_not_delete_if_not_owner
    login_as('aaron')
    delete :destroy, :id => 1
    assert_response :redirect
    assert_redirected_to todolists_path
  end

Hopefully this post will give you some insight into the refactoring process. If any of you ever see something else that needs changing, leave a comment. I’ll all ears.