Rails on the Run

Rails experiments by Matt Aimonetti

Browsing Posts tagged tip

Here is another type for attachment_fu users.

This evening I wanted to try Railroad to generate one of my app diagram. I alreay wrote my own script generating a .dot file that I usually import in omnigraffle before exporting a pretty version for my clients. The thing is, my script is quite simple and only covers models while railroad also deals with controllers.

Wanting to check on railroad, after installing the gem I typed

 railroad -o models.dot -M

and here is the ‘pretty’ error message I got.

railroad error msg

No worries, Technoweenie didn’t mess up, it’s just that I use s3 for storage and his great plugin checks on the environment to load the proper credentials. Since railroad doesn’t care about the environment, RAILS_ENV isn’t set and my model diagram isn’t generated.

To fix this issue, simply type:

$ railroad -o models.dot -M RAILS_ENV='development'

resftul_authentication is a great plugin, but not always resftful… especially if like me you dropped unit test for RSpec.

I have a set of RSpec examples I use all the time on all my projects requiring restful_authentication, obviously I always end up tweaking them because each application has its specific needs.

However, I was recently asked what’s the way of dealing with controllers specs when a controller has a limited access ?

Let’s look at the following controller for instance:

class AssetController < ApplicationController
 before_filter :login_required, :except => [ :index, :show ]

my assets_controller_spec.rb file will have the following code:

describe AssetController, "handling GET /assets/new" do

  before do
    @asset = mock_model(Asset)
    Asset.stub!(:new).and_return(@asset)
  end

  def do_get
    get :new
  end

  it "should be successful" do
    do_get
    response.should be_success
  end

end

and guess what… it will fail! Why? simply because we are trying to access an action requiring login. Right, so what’s the best way of dealing with this issue and get our test to pass?

The best solution I found was to use a simple helper that I put in my spec_helper.rb file

def login_as(user)
  case user
    when :admin
      @current_user = mock_model(User)
      User.should_receive(:find_by_id).any_number_of_times.and_return(@current_user)
      request.session[:user] = @current_user
    else
      request.session[:user] = nil
  end
end

You might wonder why I use when :user, well, in a lot of the application I’m working on, I have different levels of access and I want to tests different accounts so I the case conditional loop.

Anyway, let’s implement our helper in our previous RSpec example:

describe AssetController, "handling GET /assets/new" do

  before do
    login_as :admin
    @asset = mock_model(Asset)
    Asset.stub!(:new).and_return(@asset)
  end

  def do_get
    get :new
  end

  it "should be successful" do
    do_get
    response.should be_success
  end

end

and there you go, now your example passes properly ;)

Have fun

This morning I couldn’t remember how to get an array with only the unique properties of a Model attribute. For instance, I have a User model, and I want to retrieve the list of all my users’ cities. I also don’t want to retrieve all the attributes and only the unique rows.

in my model:

def self.cities
    User.find(:all, :select => "DISTINCT city").map(&:city)
end

Clean and simple, but for some reason I know I’ll forget and loose 5 minutes trying different things.