Posts tagged ‘ruby’

img2png

I just pushed a new web tool live. It’s called Img2Png, and it provides a simple mechanism for converting online images into PNG files. Basically, all you have to do is rewrite the image URL into one that points to png.heroku.com.

http://png.heroku.com/http/path/to/image.gif

This will redirect to a new url, which has a .png extension:

http://png.heroku.com/http/path/to/image.gif/i.png

This is pretty rough so far, especially since it was thrown together in less than four hours. The main downside is that I’ve only tested it on GIF files. It also relies on ImageMagick, which is kind of wonky on my computer. So… I have tests written for everything, but I need to loop back in later and run them once I get libpng and IM to talk nicely on my laptop.

http://png.heroku.com
http://github.com/sax/img2png

Not sure if this will be interesting to anyone else, but if anyone has improvements shoot them my way or add tickets on github. I set up a Lighthouse page for the project, as well.

sometimes rspec is easier and faster than cucumber

I’ve been writing a lot of cucumber scenarios for this project I’m working on. I like the syntax, and I like how easy it is to automate tests against the rails stack. I just ran into a simple case where rspec is much easier, quicker to write and quicker to run.

I’m using Authlogic and CanCan to authenticate and authorize requests to my application. I started doing the silly thing of double checking my controller authentication in cucumber.

This makes some sort of sense, from the point of view that it’s loading an entire Rails stack. Unfortunately it would be the source of a hell of a lot of repetition in my tests, as well as unnecessary slowness as the project increases in size. I realized this morning that actually, this can be written as a unit test for my controllers.

1
2
3
4
def authenticate_request(*args)
  self.send(args.shift, args.shift, args.shift)
  response.should redirect_to(login_url)
end

Now I can do this:

1
2
3
4
5
6
7
8
it "authenticates for its actions" do
    authenticate_request(:get, :index)
    authenticate_request(:get, :new)
    authenticate_request(:get, :show, :id => mock_model(MyModel))
    authenticate_request(:post, :create)
    authenticate_request(:delete, :destroy, :id => mock_model(MyModel))
    authenticate_request(:put, :update, :id => mock_model(MyModel))
end

I should actually abstract that it its own method, so I can quickly unit test other controllers without repetition.

This isn’t to say that I couldn’t refactor this better in cucumber. I think I may move most of my authentication/authorization testing into unit tests, however, based on the difference in complexity.

Edit: yeah, so this was covered in a Railscast almost a year ago. Still, its a big revelation to me that this should be in my specs rather than my features.

cancan

I’ve started adding authorization code to the artist portfolio cms I’m working on, using a combination of Authlogic for authentication and CanCan for authorization. I have to say I really like CanCan.

I think what I appreciate most is how accessible it is. Admittedly, I didn’t look too hard at any of the other myriad gems or plugins out there, but my initial impressions were confused ones. CanCan is extremely easy to get going.

Like with anything, however, there are little tricks. My biggest problems were in getting Authlogic to play nicely with Cucumber. Most of those were fixed with the following code in my setup.rb (in the feature/support directory, so it’s not overwritten by changes to env.rb)

1
2
3
4
5
6
7
8
require 'authlogic/test_case'
include Authlogic::TestCase
 
ApplicationController.send(:public, :current_user, :current_user_session)
 
Before do
  activate_authlogic
end

I was trying awfully hard to abstract the session creation and login code by hooking into the same sort of code I use in my controllers–mostly because I suspect that the tests and features are going to start adding up. If I can cut out the cost of calling the stack to login through a webrat request, I think it’s probably worth it in the long run, especially since that way I would only need one feature to test the login form. Then, I would have the choice in my scenario of logging in through a web request, or just setting up a login and then going straight to the real test. Alas, I was denied this simple pleasure.

Most of my trouble with testing CanCan is in figuring out when the issue is with CanCan and when it’s somewhere else. So far, the issues have all be elsewhere. There were a few stumbling blocks that have taken time to work through, however.

I’m only allowing non-admin users to edit their own user record. In my UsersController, I have this:

1
    unauthorized! if cannot? :manage, @user

As per the CanCan documentation, I have a rescue_from in my ApplicationController so that I can do something with the exception rather than throw a giant error in front of the user.

1
2
3
4
5
6
  @allow-rescue
  Scenario: edit user fails when other random user
    When I am logged in as 'user' with password 'testpass'
    And I go to the edit user page for 'user2'
    Then I should be on the home page
    And I should see "Access denied"

It took me a couple hours, I admit, before I bothered to check the Cucumber documentation and notice the @allow-rescue tag. You can set this as a system-wide variable in env.rb–that I knew. Being able to tag individual scenarios this way allows you to specify exactly which tests allow Rails to rescue_from exceptions. Without this, you see the exception, rather than the rescue.

My next issue was with my login controller. If my user has the right access, then upon login they should be redirected to an admin controller, rather than going back to the home page. Pretty standard:

1
2
3
4
5
6
7
8
9
10
11
class UserSessionsController < ApplicationController
  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = "Logged in"
      redirect_back_or_default can?(:update, Page) ? admin_path : root_url
    else
      render :action => :new
    end
  end
end

I couldn’t understand why this was not redirecting to the right place. I was logging in with an admin user, but kept being redirected to the root.

I’m still not sure why this is happening, but at a certain point I realized that it’s an issue with my Authlogic helpers. CanCan assumes a method called current_user available to the controller. This should be lazy loading the user based on the current session, which should be lazy loaded using UserSession.find. All pretty standard. For some reason, however, current_user is coming up nil right when the session is logged in.

My solution right now is this:

1
2
3
4
5
  private
 
  def current_ability
    Ability.new(current_user || @user_session.try(:record))
  end

This will probably be refactored when I know more of what’s going on, but it works for now.

Forking a 32 bit ruby process from 64 bit

Ran into an interesting issue on Twitter today. Turns out that the C headers for Quicktime are only available to 32 bit applications. This will make things difficult now that Snow Leopard is out.

I’m not sure if this is a good long term solution or not, but if your ruby is compiled such that it can run in either 32 or 64 bit modes (as it is in 10.6), you can fork a 32 bit ruby process from a 64 bit one.

This makes it possible to write a 64 bit wrapper for 32 bit code, so long as you can write it with forked processes in mind.

So, here’s a test to show the difference between 32 and 64 bit:

ruby -e "p ['foo'].pack('p').size"
8
 
arch -i386 ruby -e "p ['foo'].pack('p').size"
4

Now, the neat thing is that you can do this:

irb
>> pid = Process.fork do
?> exec("arch -i386 ruby -e \"p ['foo'].pack('p').size\"")
>> end
>> Process.waitpid(pid)

This will output a 4, exactly what we’d expect for a 32 bit process.

This would likely need a lot of work in order to incorporate into a project, but it’s encouraging to see work.

Update: @rbates just added this link to the README of his rmov gem (the gem that sparked this all off). I guess my idea isn’t completely far-fetched, as it’s the route Apple is taking with QuickTime itself. I still think it may be a viable approach in ruby, though it would complicate the code a bit.

I think that most of the complication would be in getting it to compile… if you’re creating a gem that requires compiling in 32-bit C headers, you’ll need to find a way to compile it into a 64-bit compile.

The second bit of complication would be in creating a messaging service that could fork a 32-bit process and receive coherent responses.

Hm… this might be interesting as a separate gem.