A heisenbug
Just to vent my frustrations a little bit I thought I would post a heisenbug that hit me today. Today, I realised that some pages on my production site were throwing javascript errors (jQuery Mobile / Rails 3.1). The same site on my development machine was working fine. Of course being a production site, debugging the javascript to understand what was different proved difficult. Looking at the docs on the asset pipeline (http://guides.rubyonrails.org/asset_pipeline.html) I noted a nifty little feature which is the ability to add ?debug_assets=true to the end of a url to enable debugging of the asset pipeline.
Lo and behold, as soon as I turn this on, the javascript errors disappear and the site works properly again. I am sure this is indicative of some deeper underlying problem with what I have set up – but I haven’t been able to trace it down yet.
Omniauthable – my version
So having had a bit of a rant about social authentication – and how few good examples I was able to find of how to use Devise’s Omniauthable module with multiple providers – I wanted to post here how I handled it. There are many pieces of this code copied directly from other sources. These sources are all referenced in my earlier post here.
Firstly, the heart of it, as per the Devise wiki is users/omniauth_callbacks_controller.rb. The other key files in my case are the user model (user.rb) and the devise config file (config/initializers/devise.rb). The code is below. Some points worth noting:
- I had to modify devise to allow login either via username or email in order to support twitter (and not force users to have to provide an email after authenticating). This is mostly covered in the Devise wiki here.
- In order to allow those authenticating via oauth to edit their user settings (when they have no password) I had to follow this.
- Since accounts can be edited without a password, I removed the ability to edit password via the user registration form. The only way to alter password was then via the ‘forgotten password’ mechanic via email. (So for example if after first authenticating via twitter, and the user wants to configure a password to log in directly, then they will have to first provide an email before updating their password. This is a touch clumsy but still more intuitive than forcing twitter users to enter their email just to complete the initial authentication.)
- Adding new providers is now pretty straightforward. The provider specific code is mostly confined to the provider_user_hash and provider_auth_hash blocks at the bottom of omniauth_callbacks_controller.rb
Probably still much could be improved here – but it is the closest I have gotten so far to a ‘seamless social authentication’ using Devise and Rails.
Social authentication on Rails 3.1 – a rant!
Over the past couple of months I have been developing a (rails 3.1) web application (shameless plug www.skorebug.com). Since it is 2011, I figured it needed to be mobile (enter jquery mobile) and social. For the last week or more I have really been battling with ‘social’. In particular authentication using Facebook and/or Twitter credentials (oauth). This post is about some of the issues that I uncovered that I couldn’t find covered anywhere else. I hope to actually post the code I ended up with in a later post.
I listed in a recent post all of the links I found and tried following in developing this stuff. But across all of them there were many shortcomings. What I wanted was:
- Support for Devise’s :omniauthable. It seemed from the Devise wiki entry on the topic that if I could get this working – it would be much less code to support on my part. Although in all honesty I am still not 100% clear of the benefit of using omniauthable, over Ryan’s approach
- Graceful handling of the absence of email in Twitter’s oauth response. I wanted as little friction as possible. This meant coping with users who did not provide email if they authenticated via Twitter (but the site should also allow the user to enter their email at a later date to access email specific features of course).
- Save oauth tokens for accessing respective Twitter and Facebook APIs (for example posting to the users profile)
- Allowing users to edit their details even if they authenticated via Twitter/Facebook and therefore did not have a password on my site
- Update ‘user’ details from oauth in a sane manner (e.g. Use the ‘name’ and ‘email’ from Facebook’s oauth response for the user record if these are blank)
- Constrain the social network specific code to as small as possible so that support for future networks is sane.
- At a minimum – support for both Twitter and Facebook
I was genuinely surprised that there wasn’t for in the way of examples available on the intertubes for these. Having worked with Rails for some months now – one of its great strengths is the huge amount of resources available. On almost any topic you can normally find great tutorials and articles – but for whatever reason – this area seemed a little short of great reference articles that covered what I considered to be the ‘basics’ of seamless social authentication.
The fact that Twitter does not provide email in their oauth response is probably the most significant cause of heartache. It seems that most of the articles I uncovered decide to make this ‘the users problem’ by popping up an extra screen to ask for an email address. But this is not a user problem – this is an application design problem to be solved by application designers and developers.
Devise, Omniauth and Omniauthable
So anyone who has wanted to integrate Devise and Omniauth recently has probably come across the recent Railscasts on the topic, here and here. However this was for Devise prior to 1.2 at which point the Devise guys introduced the :omniauthable method.
The problem, as highlighted by this stackoverflow question is that it is quite hard to come across a good example of Devise’s omniauthable set up with multiple providers. After much searching, the closest I could find was here. (There is another example here. It didn’t specifically include multiple providers but the structure seemed to allow for it more so than the example on the Devise wiki.)
So my next gripe with what I had found to this point was that it didn’t handle the case of twitter authentication very well. Since twitter doesn’t return an email, the ‘Railscasts’ approach was to ask for an email upon signing up. This seemed too high friction for me and I wanted something that allowed users to register via twitter without having to provide any extra information.
So I was just in the process of trying to meld all of this together into my own solution for this post, when ‘one more Google search’ (after many) yielded a wonderful gist here. This finally seems to answer most of my issues in a sane manner. I am about to give this a try now…. fingers crossed……
Web App Deployment
Have battled to deploy my first Rails 3.1 / jQuery Mobile site over the last couple of days. It is finally live at www.skorebug.com (the jQuery Mobile but begins when you try and log in!)
A couple of things that bogged me down for ages:
- How to deploy? The Rails world seems to love Capistrano – but for a single developer/single server website it seemed overkill. Was tempted to just manually ftp files to my server but that made me feel yucky. Finally found a nice compromise using git. Probably millions like it – but this blog post got me started: http://pixelhum.com/blog/using-git-for-deployment
- Setting up the server? Part 1: How to actually install Ruby, Rails, Rubygems etc. I had used rvm in dev and liked the idea of using it too. Battled with a bunch of things till I uncovered this: https://github.com/joshfng/railsready It was an absolute life saver and took care of all the ‘boring bits’ nicely 😉
- Setting up the server? Part 2: Where to put the files (used it in dev – seemed like a good idea) and a bunch of other questions. The Rails community seems to have great materials on how to get started with the dev bit – but I really struggled to find good resources about deployment (that weren’t 60 pages long). The secret that didn’t seem well documented is to point your web server at the /public directory of your Rails app (and essentially copy everything from your dev environment to production). This seemed counter-intuitive at first – since on Rails 3.1 I had never touched the /public directory (other than to delete index.html 😉 I guess that is the price you pay for starting to learn Rails 3.1 whilst it is still unreleased.
- X-Sendfile!!! At this point the basic app was working nicely except for images. It puzzled me for ages – but eventually discovered that X-Sendfile had to be configured for my web server (Apache in this case). Again something that was not obvious from the documentation. Even the apparent option on config/environments/production.rb to disable X-Sendfile didn’t seem to work as expected. So yes – you need to make sure that X-sendfile is installed on your web server and enabled for each of your Apache VirtualHosts. I did find a reported ‘Issue’ under the Rails project on github – it seems that something has changed in 3.1 in this regard – but as a n00b – it made no sense whatsoever 😉
So finally – a process that should have taken a couple of hours was finished after a couple of days – but at least it is finished!!
(Note the site itself is functional – but far from “finished” – so if you are one of the three people in the world that read this post and go to the site (Hi Mum!!) – please be gentle 😉
jQuery Mobile, Rails, Buttons and Headaches
So I wanted to add a button to my Rails 3.1 / jQuery Mobile app that triggered an AJAX action (HTTP POST). It should have been easy…
Firstly, I tried <button_to>… however this creates a form. The problem I had was that jQuery Mobile was triggering on POST and one GET for each click. In theory you can add ‘data-ajax=false’ to tell jQuery Mobile to leave this alone – however there is no way in the button_to helper to add attributes to the <form> tag (they all get added to the child <input> tag.
So I changed the ‘button_to’ to a ‘link_to’ (with :method => :post) and things seemed to go swimmingly at first.
However a little down the track I wanted to be able to disable/enable this button. in jQuery Mobile I could easily do this by calling $(‘…’).button() followed by $(‘…’).button(‘disable’) – however I ran into two problems. Firstly there was no easy way to have the button disabled on initial page load (I could run that but of JS on page load – but I really just wanted to add “disabled” to the button element.) Secondly, since link_to still included the underlying link after jQuery Mobile had styled it to look like a button – calling ‘disable’ made it look disabled but really didn’t disable it at all.
A simple button was causing me a lot of headache. It seemed that the ‘right’ element to use here was in fact a ‘button’ (since it was semantically correct and it had the correct ‘disable’ functionality). The problem became how to add ‘data-ajax=false’ to the form generated by the button_to helper.
My current workaround is simply to create the form directly each time I want a button. It looks something like this:
<%= form_for @event, :url => :undo_event, :remote => true, :method => :post, :html => { :class => “button_to”, “data-ajax” => “false” } do |f| %>
<%= f.submit “Undo?”, :class => “undo-button”, :disabled => true, “data-icon” => “back”, “data-iconpos” => “top” %>
<% end %>
I guess the other approach would be to make a helper that looked like ‘button_to’ except that it allowed options to be passed to the parent form.
Rails 3.1, jQuery Mobile and the Asset Pipeline
I haven’t really used any version of Rails before 3.1 – so I am not intimately familiar with the ‘way it used to be’. From what I understand, all of the js, css and images associated with a library like jQuery Mobile would have been included under /public. The problem with this is that /public then become stuffed full of a mixed bag of files with little organisation.
So enter Rails 3.1 and the asset pipeline and my adventures with jQuery Mobile. Following the guide here (http://ryanbigg.com/guides/asset_pipeline.html) I placed the jQuery css and js files under /vendor/assets/stylesheets and /vendor/assets/javascripts respectively. This worked well. These files could be loaded directly via include tags such as: <%= javascript_include_tag “jquerymobile.js” %>
Using this approach however the images used by jQuery Mobile had to be placed under /public/assets/images in order to be found. This worked – but made no sense to me… to have the js and css under /vendor and the images under /public. So I went searching for a better way.
The first clue was when I found this site (http://getsprockets.org/installation_and_usage). This actually shouldn’t have been that remarkable – except that it didn’t seem to be referenced from any of the Rails docs on the Asset Pipeline that I could find. The ‘provide’ directive is the one that is useful here.
So I returned to look at jQuery Mobile and discovered that all of the images or loaded by the css. So alongside my jquery-mobile.css in /vendor/assets/stylesheets I placed a ‘vendor.css’ that was a manifest file that included:
*= require “jquery-mobile”
*= provide “..”
(Forgive the lack of proper syntax highlighting…. that is a job for another day 😉
The images for jquery mobile were placed in /vendor/assets/images as you would expect. And I this point I was sure I had it licked. But I consistently got 404’s for any attempt to access the images. I tried all sorts of variations of the path for the provide directive with no success. Then finally I came across this post (http://stackoverflow.com/questions/6213218/rails-3-1-and-image-assets) which mentioned that the ‘/images’ portion of the url was being stripped. However ‘/images’ was coded throughout the jQuery Mobile css. So I added another ‘images’ subdirectory (/vendor/assets/images/images) and put the jQuery Mobile images there and viola – success.
The repeated images directory is a bit ugly – but much less ugly than having js and css in /vendor and the images in /public – so that counts as a win.
Given that I am a total n00b in this – I am sure that there is “a better way” – but at least this is working.
Adventures with Rails 3.1 and jQuery Mobile
Many of us can think of many reasons for starting a blog, but never actually get around to it. And then one small thing comes along and pushes you over the edge to start. In this case it is my current pet project…… I am putting together a web site. Big deal!! So to keep things interesting I am using the latest cutting edge Ruby on Rails (3.1.0rc4 at this point) (www.rubyonrails.org) and the shiny new jQuery Mobile (Beta2pre at this point) (www.jquerymobile.com).
Since I am using such ‘new’ tools, I am running into a myriad of little issues – some of which I am not able to find great answers for online. Hence the blog. It will give me a place to post the stuff that I am finding along the way that is useful to me (it isn’t much harder than putting it in a text file which is the other option) and maybe it might be useful to someone else to.
Over time – who knows what else will get added (if anything)…
First post
Well this is it. My first blog post. I have thought on and off for years that I “should” do a blog… but when to find the time?? Would I keep it up?? What to write about?? I looked at Blogger and WordPress… but all the posts seemed so ‘big’ that it was daunting to start. Tumblr however seems to encourage smaller, shorter posts. Maybe that I can do. So tonight, between packing away the dinner dishes and giving the kids a bath is my first blog post.
What will the blog be about? Well only one way to find out….
Recent Comments