Ajax Login with Devise
There are partial solutions to logging in through Ajax with Devise littered throughout the Devise mailing list, so it took me a little while to put all of the pieces together. Below are all of the pieces a Rails application using Devise needs to allow Ajax logins.
First create an extension for Devise’s sessions controller. We want the response to be in json, so we change the recall in the authenticate! method to go to our own custom method that returns a json response with a failure message. This should be placed in app/controllers/sessions_controller.rb
Next, tell Devise to route all session requests to the new controller we created. With a default route setup for Devise (no renaming of routes), you would do so as follows in config/routes.rb.
devise_for :users, :controllers => {:sessions => 'sessions'}
We need to tell Devise not to use HTTP authentication. If we don’t, a 401 response will be sent back and cause a username and password dialog pop up! We also need to add :json to the navigational formats. This mean any request that ends in .json will pass through fine. In config/initializers/devise.rb, you need to have the following configuration items set.
config.http_authenticatable_on_xhr = false
config.navigational_formats = [:html, :json]
Let’s set up a simple form that takes a email and password. Mine is written in haml.
Finally, we need to post the login data to our application using Javascript (jQuery in this case).
That should do it. Don’t forget to restart your application so your new routes take effect!
Troubleshooting
One of the errors I came across that threw me for a loop was:
Unknown action
AbstractController::ActionNotFound
It turned out I was receiving this error because I had the session routes defined twice. Type rake routes | grep sign_in and make sure you only have one instance of sign_in.
Bearable XML Schema with Clojure
Writing XML schemas by hand is rough, so I wrote an extension to Stuart Sierra’s prxml library that makes writing XML schemas slightly more bearable.
For instance, while working on Streamigator I needed to validate the following:
With XML, I would have written this schema:
With Bearable, the above schema was shortened to:
As you can see, the Clojure code matches up much closer to the document I needed to validate. Intrigued? You can view the code and up-to-date documentation at Bearable’s GitHub repository.
If you think Bearable could be improved let me know in the comments or through email!
Handling Underscores in Subdomains with Ruby
Ruby’s URI library follows RFC 1034 to determine if an URI is valid. RFC 1034 does not permit underscores in subdomains. When URI tries to parse a subdomain with an underscore, it gives the following error:
URI::InvalidURIError: the scheme http does not accept registry part: sub_domain.host.com (or bad hostname?)
Unfortunately, several real world websites include underscores in their subdomains. Originally, I wrote my own URI parser that hands off most of the work to URI except for when there are underscores in the name. Recently I came across the library Addressable, which handles underscores completely fine, so I switched to using that.
To get the page text of a URL that contains an underscore in the subdomain, use the following code:
rspec Version Conflicts with autotest
Earlier today I made some changes to a project I’m working on and when I went to run autotest I received the following error:
You have already activated rspec-core 2.5.1, but your Gemfile requires rspec-core 2.4.0. Consider using bundle exec.
After a search on Google, I noticed most people recommended adding a version number to rpsec in your Gemfile and then rerunning bundle install. I already had a version specified in my Gemfile, so that didn’t apply to me. What did work is running gem uninstall rspec-core and then choosing the 2.5.1 version. It looks like autotest will disregard what is in your Gemfile and just use the newest version of rspec that is installed.
OSGi and Thread Class Loaders
A short while ago I was tasked with changing an application that uses Toplink so that it will work inside ServiceMix. One of the problems I ran across was a ClassCastException when I tried to initialize Toplink. As is typical with OSGi and ServiceMix, the ClassCastException was not the real issue, but rather a symptom of the problem.
After digging through the internals of Toplink, I realized that the real issue was Toplink’s use of the current thread’s class loader. This would work normally, but when running inside ServiceMix the class loader for the current thread is not always the correct class loader for Toplink.
In order to fix the problem, I saved off the old thread’s class loader, changed the thread’s class loader to the correct loader, initialized Toplink, then restored the thread’s class loader to the one I saved off. Here’s the code:
After I made those changes it worked fine. Toplink initialized successfully and I was able to interact with the database.