These days, if you are building a web based service then you are also going to be building a iPhone, Android, or mobile web site to complement it. If your mobile apps require a user login then you need to provide an authentication method on the server side that can be called via a secure REST interface.
If you’ve built your web app using Rails and you follow convention then you should be able to easily expose your existing login REST method via the same controller that handles your web login. But I’ve never been a fan of mixing web services which are only used by external apps into the same codebase as your website which never uses them. By pulling your web service code out into it’s own app you keep the two separate code bases clean and dedicated to their own task, and you can iterate on them individually.
In our web app we used Authlogic for authentication, one of the things it takes care of is encrypting and decrypting passwords during authentication so we needed to ensure that the separate web services app also used Authlogic. We could have just created another Rails app for the web services but we ended up using Sinatra which is much simpler to use for a small set of services. There was one catch with running Authlogic in Sinatra which I wanted to share and hence the purpose of this post.
The Sinatra app itself is quite simple, I’ve posted a project template in Github as a reference.
In our case we built an iPhone app, performed our own encryption of the password on the iPhone before sending it over the air, then decrypted on the server side before passing it as normal to the Authlogic valid_password? method.
But we were getting the exception:
undefined method `valid_password?’ for #<User:0x007fd29dd269b0>
A web search for the exception found others receiving a similar exception when using Authlogic but none of the suggested solutions worked for me.
I eventually figured it out, the catch is when using Authlogic in a Sinatra app your user model which contains the acts_as_authentic must be included AFTER you have created your database connection.
Take a look at line 31 in the source for the acts_as_authentic method
def acts_as_authentic(unsupported_options = nil, &block)
# Stop all configuration if the DB is not set up
return if !db_setup?
It first checks if you have a database connection, if not then it simply returns. Ideally it should have raised an exception so we know at the point of error what caused it to fail, instead the error manifested itself later when we tried to use the user model which had not been initialized by Authlogic and hence the valid_password? method did not exist.
I have made the change in my own fork and submitted a pull request so perhaps we’ll see it in a future release.