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:
- 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.
- 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
Posted by trevor
Mon, 29 May 2006 01:16:40 GMT
A few years back, while I was building my house, I downloaded a demo copy of Sketchup to help visualize how everything would look. It’s a fantastic tool for 3D design, one of those rare pieces of software that just makes sense.
Unfortunately it’s also software that costs about $500 USD and as much as I wanted to, I simply couldn’t justify the expense. My love affair with Sketchup was doomed to be just a few short weeks as the demo period quickly slipped away.
Sketchup did leave me with a legacy though: Ruby. It ships with a ruby interpreter and has hooks to extend the software with Ruby scripts. Had I not seen the Ruby/Sketchup integration I probably wouldn’t have given Rails a second look when I stumbled across it a year and a half (gosh!) ago.
Okay, that’s enough nostalgia. The real point here isn’t whether I owe a debt of gratitude to a 3D modeling program for more than a year of fun, full-time work with Rails…
The real point here is that Google bought Sketchup and they are releasing cut-down free versions. I think that’s pretty big news and I have absolutely no idea how I missed it.
They’ve already released the free version for PC and apparently a free version for OS X is in the works as well.
I am so chuffed about this. It’s going to make designing my kids’ backyard playstructure a breeze.
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
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
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:
- Users should not be able to grant themselves administrative capability
- 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