Giant Robots Giving Me Flashbacks.

Posted by trevor Mon, 07 Jan 2008 23:00:12 GMT

This morning I checked my feed reader and was instantly transported back to 1992, when I was working for a small independent software vendor.

So please indulge me while I tell you a little bit about the company, what I learned, and what brought it all rushing back.

Read more...

Posted in code | 2 comments

How To: Uncountable Names in RESTful Routes

Posted by trevor Mon, 19 Mar 2007 05:03:23 GMT

A couple of times I’ve noticed people saying that uncountable names (like sheep and fish) can’t be used with resource routes in Rails. Well, they can.

# in config/routes.rb
map.resources :fish

In the above example there is a conflict between the generated url helpers for the ‘fish’ collection and the generated url helpers for members of the ‘fish’ collection. Because ‘fish’ is uncountable, both are called fish_path or fish_url. And because of the way routes and url helpers are created in a map.resources call, the member url helpers override the collection ones.

So using the above example, calling fish_path() raises an error like:

ActionController::RoutingError: fish_url failed to generate from {:controller=>"fish", :action=>"show"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["fish", :id] - are they all satisifed?

Thankfully that’s not the end of it. You just have to add a :singular argument when defining your resources:

# in config/routes.rb
map.resources :fish, :singular => :fish_instance

# in your code
fish_path() #=> /fish
new_fish_instance_path() #=> /fish/new
fish_instance_path(1) #=> /fish/1
edit_fish_instance_path(1) #=> /fish/1;edit

That’s all.

Posted in code | no comments

New Plugin: xls_fixtures

Posted by trevor Tue, 17 Oct 2006 17:54:46 GMT

Here’s a little something I whipped up that’s proved useful.

Yaml is a pretty good format for storing fixture data but it can be a real pain to set up a bunch of fixtures with repeating or incrementing data. There’s a much better tool out there for that – Excel.

One way you can ease the pain of generating reams of fixture data is to build it all up in Excel and export your spreadsheets as csv files and tell Rails to use csv fixtures. Unfortunately I couldn’t find a way to have a moniker (my name for the non-indented line in your yaml fixtures) in the csv files so that I could refer to fixtures by name in my tests.

So what I’ve done is to write a little plugin and rake task that converts xls files into yaml fixtures. See:

http://svn.protocool.com/public/plugins/trunk/xls_fixtures/

Note that it requires the ‘parseexcel’ gem (as in “gem install parseexcel”) and you need to arrange your rows and columns as per the README file in the plugin.

Posted in code | 2 comments

A little (more) syntactic sugar in Rails

Posted by trevor Mon, 12 Jun 2006 17:48:56 GMT

This little extension to Ruby’s Array class is making the rounds:


class Array
  def sum
    inject(0) { |m, v| m + v }
  end
end

# Use it thusly:
[1,2,3,4,5].sum # => 15

Nice. But what if we want to sum a member of each array element, such as the ‘price_cents’ attribute on a bunch of ActiveRecord objects?


@order.line_items.collect {|x| x.price_cents}.sum
# or (my preference) using Symbol's to_proc method:
@order.line_items.collect(&:price_cents).sum

Even with the sugar that Symbol#to_proc adds, it’s just a bit… well, blech. We can do better:


class Array
  def sum
    if block_given?
      inject(0) { |m, v| m + yield(v) }
    else
      inject(0) { |m, v| m + v }
    end
  end
end

# Now we can say:
@order.line_items.sum(&:price_cents)

That’s just so much clearer.

Update: a recent changeset in the rails trunk adds a ‘sum’ method to Enumerable. It’s different from what I present above in that it only works with a block – which is okay for me because that’s my main usage pattern anyhow.

Posted in code | no comments

A Rails tale of caution: functional tests hanging with controllers in subdirectories

Posted by trevor Tue, 30 May 2006 23:27:05 GMT

This afternoon I was hit by a real headscratcher – documented here for future googlers looking for information on: functional tests hanging controllers subdirectories :-)

I added in some tests for controllers that were in a subdirectory (as in “./script/generate controller boo/hoo“) and suddenly rake started hanging.

I could run individual functional tests just fine but as a suite – forget it.

The source of the problem turned out to be twofold:

  1. in test_helper.rb we alias the get and post test methods so that we can optionally capture all of our output and run it through a validator.
  2. the require line that ./script/generate creates for loading test_helper.rb in your functional tests is relative to the current file’s directory. For functional tests in subdirectories you get a require argument ending with ”/../../test_helper” rather than the one ending with ”/../test_helper” as you do in top-level functional tests.

Even though those two different require lines point to the same file, from require’s perspective they are different – so the file is loaded twice.

And that’s a big no-no if you are doing a simple method alias without checks against doing it twice.

The bulletproof solution is to have tests use File.expand_path() on the argument to require. But if the generators keep spitting it out as they do now it’s one of those “pushing water uphill” situations. I smell a patch.

For now, I’m just wrapping my alias calls with a check of self.instance_methods to make sure the alias hasn’t already been done.

Posted in code | no comments

Snippet: using 'inherited' to set filters in controllers

Posted by trevor Fri, 26 May 2006 22:51:37 GMT

One of my apps has a set of controllers in an ’/admin’ directory. They all must have a :login_required before_filter and they all must define an authorized? method that checks if the current user is an administrator.

For a couple of reasons the idea of having a special “AdminController” which everything under ’/admin’ would inherit from (and that set up the filter and authorized? method) kind of irked me.

First, there was the name clash – AdminController becomes ‘admin’ in routes and that clashes with my directory called ‘admin’, so I’d have to choose a name like “AdminBaseController” or some-such. Blech.

Second, I just didn’t like the extra file for the base controller. Call me picky, I can take it.

What I wanted was a way to say “if the controller is in the /admin directory then it needs this filter and this method”.

Class#inherited to the rescue. Here’s what I put in /app/controllers/application.rb:

# For all controllers in the 'Admin' namespace we set
# the login_required before_filter and define an authorized?
# method that checks user.is_administrator? 
def self.inherited(subclass)
  # call super first - otherwise any before_filters we add are lost
  super
  if subclass.name.split('::').first == 'Admin'
    subclass.before_filter :login_required
    subclass.send(:define_method, :authorized?, Proc.new {|user| user.is_administrator?})
    subclass.send(:protected, :authorized?)
  end
end

This is fine for my present needs. If controllers under /admin start to need any more shared behavior I’ll just bite the bullet and do the AdminBaseController thing – but for now this is clean and works.

Posted in code | no comments

Best Practices: a strong case for attr_accessible part 2

Posted by trevor Wed, 24 May 2006 22:31:58 GMT

This is a followup of part 1 which you should read before continuing here.

So… are the requirements satisfied? No.

It’s possible for any user to delete a project that they don’t actually own. More specifically, it’s possible for a user to arbitrarily assume ownership of any project they know the id of. After that, the project is theirs to do with as they choose.

The code that allows you to assume project ownership is here:

class UserController < ApplicationController
  def save
    current_user.update_attributes(params[:user])
  end
end

class User < ActiveRecord::Base
  attr_protected :is_administrator
  has_many :projects
end

Spotted it yet?

Read more...

Posted in code | 9 comments

Best Practices: a strong case for [redacted] part 1

Posted by trevor Wed, 24 May 2006 03:10:00 GMT

Tonight I decided to tip over my blog-post idea pickle jar and see if anything interesting fell out. This is the first one that didn’t get crumpled up and thrown in the trash (gotta love that pickle jar).

Instead of just blathering on I’d like to show you a few lines of code and invite you to answer a pop quiz:

class UserController < ApplicationController
  def save
    current_user.update_attributes(params[:user])
  end
end

class ProjectController < ApplicationController
  def destroy
    @project = Project.find(params[:id])
    if ( @project.user_id == current_user.id ||
      current_user.is_administrator? )
      @project.destroy
    end
  end
end

class User < ActiveRecord::Base
  attr_protected :is_administrator
  has_many :projects
end

class Project < ActiveRecord::Base
  belongs_to :user
end

Before anyone gets too bent out of shape – don’t worry about the stuff you don’t see. Everything you need is there.

Here’s the requirements we’ve been given:

  1. Users should not be able to grant themselves administrative capability
  2. Only administrators or the project’s owner can delete a project

And here’s the pop quiz: are those requirements satisfied? Why or why not?

Bonus points (for what they’re worth) will be given if you can tell me what I’m going to make “a strong case for” in the title of this post.

I’ll post my answers tomorrow (Wednesday) at 10:00 PM GMT.

[Edit] someone asked so I’ll clarify: the current_user method in the controllers always returns the correct user.

[Edit] another clarification: we can assume that actions not shown in ProjectController such as edit/save perform the same checks as ProjectController#destroy before doing anything.

[Edit] Part 2 is available now.

Posted in code | 11 comments

RutBusting - start at the end

Posted by trevor Fri, 03 Mar 2006 12:10:05 GMT

I’ve been in a tremendous rut. Not the one or two day glitch affair that happens from time to time but an honest to goodness, slow… grind… to… a… complete… stop.

Along the way I discovered that there’s no heroic effort that can save you from an epic rut, no massive push or flash of brilliance that will get you back into a state of flow, nothing that will somehow erase all the hours burned while staring blankly at the screen.

To get out of a genuine rut you need to do something much smaller and very specific.

Start at The End

A runner visualizes crossing the finish line, a climber visualizes grabbing a hold. Nothing earth-shattering here: you concentrate on the end goal and work backwards, mapping out how to get there.

Just make sure you really know what “the end” really is.

As a software developer, I thought “the end” was code and this is partly what kept me in my rut. “Just write some code, dammit!” I was wrong, of course, because while in my rut I wrote quite a lot of code. It’s just that all of it was crap so I deleted it as fast as I wrote it. Okay, maybe not all of it was crap – when you’re in a rut everything sucks regardless of whether it really does suck.

It wasn’t until a few hours ago that it occurred to me that whatever I’m working on is never considered finished until it’s been checked-in to source control. My “the end” is svn commit -m and being able to type that command makes all the difference.

Practice getting to The End

Once you know what “the end” is, you need to practice getting there over and over to remind yourself what it feels like. You need a series of tiny victories to rebuild your confidence and prove to yourself that you’re not a complete waste of skin.

Tonight I chose three minor issues with our code to fix. All of them were a simple search-and-replace so they didn’t require much thinking at all. Putting effort into something so trivial seems kind of pointless, especially when you consider how far behind I am on the task that was stuck with me.

But I got to type svn commit -m three times and it felt great.

So, for me at least, today’s catchy buzzphrase is(with a tip of the hat to Glengarry Glen Ross):

Always Be Committing

I’m out of this rut – I can just tell.

Posted in code

Rails gets better support for namespaces.

Posted by trevor Mon, 30 Jan 2006 17:51:52 GMT

If you’ve ever worked on a large rails project, that one /app/models directory can start to look a bit daunting filled with a ton of files. In my opinion it contributes to a fear of adding classes.

A recent changeset adds better support for auto-loading of classes within modules. It also adds support for marking classes as Reloadable even if they don’t inherit from Rails core classes like ActiveRecord::Base.

This is seriously good news because it makes organizing your classes that much easier, encouraging you to simplify your architecture by (paradoxically) adding classes.

Posted in code

Older posts: 1 2