redirecting devise

Been playing around with Devise for a project that I’m helping a friend with. I ran into something that isn’t too intuitive, so I figured this would a good candidate for a post.

I have the following desired workflow:

  • Anonymous user submits form
  • Controller redirects to login/signup form
  • User logs in
  • Controller posts original form

With Devise, I found that I was being redirected back to the root_url no matter what I tried to throw in the way in the controllers. After I poked around a bit on the documentation, the google group and various blogs I came to the Warden documentation.

Note: Warden is awesome.

I realized that one way of solving the problem would be to add a Warden before_failure callback to my Devise configuration. This would intercept the request and save it to the session, so that I could come back to it in my application_controller. Devise provides an easy way to redirect out of a login, just no method to capture the original request (unless I’m completely missing something).

My attempts to put this into code suffered abject failure.

Fortunately I found this: http://rubyglasses.blogspot.com/2008/04/redirectto-post.html

Turns out you can’t redirect to a POST.

Philosophy of HTTP aside, this makes my desired workflow impossible. The only way to mimic it would be to add model creation logic to my ApplicationController#after_sign_in_path_for… and that would make me cry. Instead I’ve changed my workflow so it works with a GET:

  • Anonymous user submits form
  • Controller redirects to login/signup form
  • User logs in
  • User redirected back to form, which is filled out

Here’s my devise initializer:

Devise.setup do |config|
  # ... normal setup options
  Warden::Manager.before_failure do |env,opts|
    request = Rack::Request.new(env)
    request.session[:return_to] = request.env['REQUEST_METHOD']=="GET" ? request.env['action_dispatch.request.path_parameters'] : request.env['HTTP_REFERER']
    request.session[:return_params] = request.env['action_dispatch.request.request_parameters']
  end

And here’s what I added to my application_controller.rb:

def after_sign_in_path_for(resource)
  if request.session[:return_to].is_a? String
    [request.session[:return_to], request.session[:return_params].to_query].join("?")
  elsif request.session[:return_to].is_a? Hash
    request.session[:return_to].merge!(request.session[:return_params])
  else
    super
  end
end

Now in my form action, I need to make a small update:

## before
  @thing = Thing.new
## after
  @thing = Thing.new(params[:thing])

So after logging in, the user is redirected back to the form. All the params are there in the GET, though, so it fills itself out.

I could see cases where you would NOT want to do this… confidential information in a GET request may show up in a browser’s history, even if the page content passes over SSL. But for anonymous information, this works out pretty nicely.

ipad webkit

I can’t tell yet for sure, but I think the iPad Safari does finger interactions slightly differently from the iPhone version. On clicking something with a hover state, it activates the hover state. Then when you click again, it activates the link.

This is confusing. It also makes the coding of touch interactions trickier when taking both phones and tablets into consideration.

Just saying.

rails3 engine as gem vs plugin

I’m trying to update a 2.3.5 engine to work with 3, and am in somewhere in the steep logarithmic climb of the learning curve. Fortunately @josevalim has a gem out called enginex that sets things up quickly. I was attempting to set up a new engine project with tests, and doing it manually was going absolutely nowhere.

Note: It’s a bit frustrating that I can’t tell the difference between my personal attempts and the output of enginex, and why the one works but the other didn’t. At least I have something that works now, though.

I just ran into something interesting, which is that my engine in the plugins directory gives an error, “‘my_engine’ is a Railtie/Engine and cannot be installed as plugin”. I see no documentation indicating what is the preferred way to load engines, so I’m skipping the entire thing and turning my engine into a gem.

Perhaps this is the preferred way of managing engines?

Unclear. Again, what it comes down to is that the gem works. I guess this is the pain of riding the edge, with such a tremendous change in the framework.

UPDATE: This gist explains, among other things, why the way I was setting up my engine was not working as a plugin: Rails automatically reads plugins as engines, so when I was specifying an Engine class it was getting loading the engine twice.

rails 3, finally

I’ve finally started diving into Rails 3, with a few issues. In general the way you code an application works the same, with some changes in syntax. Behind the scenes there are a lot of differences. Mostly I’m finding that the complications are with plugins and gems.

Also, it came up in an online conference that Rails3 and Ruby1.9 is easier on 1.9.2-head rather than 1.9.1. I’m not sure if some of my earlier problems were because I of this, but since updating ruby versions things have been stable. [Note: 1.9.2-head and 1.9.1-head may be the same thing based on what I'm seeing online, at least from rvm's point of view]

Last I touched cucumber was about a week and a half ago, but avoiding massive failure was painful enough that I stopped fiddling with it… at that time, it looked like the main repository was only Rails 2 compatible, and installing it at all required a link directly to @alg’s fork.

Rspec is a little further along, in that you can install it to the system using rubygems.

gem install rspec-rails --pre

This is not so bad. It’s a little rough around the edges, as features are being added group by group. As of yesterday, it’s in an a9 release. Route specs are not yet supported, causing some red in my terminal. But other than that it’s already very usable.

The main issue so far is that @ryanb’s CanCan is raising unexpected nil errors in my specs. This issue relates to the problem… at the moment I’m unclear whether the issue is in CanCan or with Rspec… my guess is the latter, but unfortunately they’ve taken down their issue tracker to avoid premature bug submissions. That said, digging through rspec-core is kind of fun.

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.

vmware + ubuntu + wine + blackberry simulator

In the process of testing some mobile web code in a Blackberry, I’ve realized how much I hate BlackBerries. Not the device really, which I could care less about. Really, it’s the software, and by software I mean browser. I hate the BlackBerry browser.

Its rendering is inconsistent between operating system version as well as devices. Not just little inconsistencies, but really large ones that are impossible to predict. How about a very simple bit of 10-year old HTML standard as follows:

1
<input src="path/to/img" type="image" />

In testing, a device would render the image one page, but not render the image on another. On some pages, the browser would render the image in one input, but not render the image in another. So… you support the tag… sometimes? But not all the time. If the browser feels up to it at the moment.

Another bit of horrible-ness that I can’t even attempt to explain. A user clicks on a link to a restful URL. The browser goes to… a different URL. Not just using the wrong HTTP method, which I could understand. But a completely different URL? Uh… what?? What do you expect me to do with that, BlackBerry? Look forward to the constant suspense of wondering whether a phone will follow the links I suggest to it?

Anyways, I’m trying to get a BlackBerry simulator to run on my mac. My first attempt was a complete failure, so here’s me documenting steps to make sure that I can repeat any potential success.

First of all, I’m doing this on a VM of Ubuntu running in VMWare. Trying to get wine to run natively on my mac wasn’t quite a dead end… after a certain point I just realized that I’d have to use macports or something similar in order to resolve the dependencies with any sort of ease.

  1. sudo apt-get install build-dep wine
  2. sudo apt-get install fakeroot
  3. git clone git://source.winehq.org/git/wine.git ~/wine-git
  4. cd ~/wine-git
  5. ./configure
  6. make depend && make # walk away for an hour
  7. sudo make install
  8. # download the simulator from the blackberry site
    • for me this was BlackBerry_Simulators_4.6.1.94_8900.exe
  9. wine BlackBerry_Simulators_4.6.1.94_8900.exe /extract:c:\\
  10. wine msiexec /a c:\\SimPackageInstaller.msi /qn
  11. wine ~/.wine/drive_c/Program\ Files/Research\ In\ Motion/BlackBerry\ Smartphone\ Simulators\ 4.6.1/4.6.1.94\ \(8900\)/fledge.exe

So, the big caveat is that this doesn’t work yet. The simulator loads, but the OS doesn’t run in the simulator. I’ll experiment and see if I can’t find out what’s going wrong.

Note: installing wine using apt-get did not work. I found on a blog somewhere that the package is out of date, and certain more recent fixes make wine more compatible with the simulator.

Edit: Finally got the simulator to run without crashing. It still can’t reach the network, but at least this is something:

  1. wget http://www.kegel.com/wine/winetricks
  2. sudo mv winetricks /usr/local/bin
  3. winetricks corefonts vcrun6 gdiplus # runs as local user
  4. winetricks comctl32 comctl32.ocx msls31 msxml3 msxml4 msxml6 riched20 riched30 tahoma #not sure if these are really necessary

Now… why is the blackberry browser not connecting to the internet?… from my blackberry simulator, through my windows emulator, through my ubuntu virtual machine, to my mac’s network stack. Whew.

cucumber, authlogic and factory_girl

I’m diving back into a Rails project that I started last summer, before I got sidetracked with… you know, having a job and crap. I’m surprised by how many cucumber features I’d written. I’m even more surprised by how little implementation is there. Why did I write so many features without making any of them work?? I have to assume that I must have lost something in transferring between computers, or I reverted a bunch of code without committing it… yeah… that’s it.

Anyways, I figured I’d use authlogic for my authentication, factory_girl for my factories and finally give formtastic a try. Here are really helpful links:

http://www.claytonlz.com/index.php/2009/11/cucumber-table-transformations-with-factory-girl-sequences/
http://sentia.com.au/2009/06/adding-your-own-login-method-to-authlogic/

A handy thing about table transformations is that you can build your objects without really having to care about the underlying table… the point of Cucumber, I guess. With authlogic, though, it allows you to do this:

1
2
3
4
5
Transform /^table:Login,Email,Password$/ do |table|
  table.hashes.map do |hash|
    {:username => hash[:Login], :email => hash[:Email], :password => hash[:Password], :password_confirmation => hash[:Password]}
  end
end

So, I just have to pass the password in once, but behind the scenes it gets transformed into both :password and :password_confirmation. Then using formtastic, my login view becomes this:

1
2
3
4
5
6
7
<%- semantic_form_for @user_session, :url => user_session_url do |f| -%>
  <%= f.input :username, :hint => 'login in with username or email.' %>
  <%= f.input :password, :as => :password %>
  <%- f.buttons do -%>
    <%= f.commit_button 'Login' %>
  <%- end -%>
<%- end -%>

My UserSession and User models then work it out that :username can be equal to either User#username or User#email.

1
2
3
4
5
6
class User < ActiveRecord::Base
  acts_as_authentic
  def self.find_by_username_or_email(login)
    find_by_email(login) || find_by_username(login)
  end
end

I had started to build some role-based authorization, but now that CanCan is more developed it’s probably time to look at that. My initial idea was to use Ruby metaprogramming to define new user methods based on the roles assigned to a user. I guess that’s still a valid approach, and theoretically would work with CanCan… the gem may make my approach redundant, however. I can definitely foresee errors based on Role objects overlapping the ActiveRecord namespace. I think I’d have to build in validations to check the User namespace before saving new Roles. weirdness.

no rspec yet for rails 3

Taking a walk through the Rails 3 pre code, there are some interesting differences in there that I’m not sure I totally understand. I think the biggest obstacle to my using it, however, is that there is no RSpec yet. I don’t even want to look at Cucumber, since its lack of appearance in my Rails 3 generator list look pretty suspicious. [actually, I did play around with RSpec and Cucumber for a while to see if I could force through an installation, but quickly gave up when I realized how painful it would be]

So… looking forward to Rails 3, but I don’t think I’ll seriously consider trying to make anything with it until I can write specs for my code.