Scott W. Bradley

in which scottwb thinks out loud

Fork me on GitHub

jQuery Mobile and Rails UJS Method Links

| Comments

Rails UJS and jQuery Mobile do not play nice together when it comes to combining Rails UJS’s handling of non-GET/POST links with jQuery Mobile’s data attributes such as data-ajax, data-direction, and data-transition. This post demonstrates a quick hack you can use to remedy this.

Auto-Focus the First Form Element With jQuery Mobile

| Comments

Imagine a series of pages with simple forms on each of them. With jQuery Mobile, you’ll usually end up transitioning between these pages using AJAX and nice slide transitions. Since all your forms will end up in the same document, you need to be careful to give them unique IDs if you want to access them from javascript.

One thing I like to do with forms, especially on mobile platforms, is to automatically highlight the first field in the form when it comes in to view. The trick with jQuery Mobile is that with AJAX loading, pre-loading, and BACK/FORWARD buttons, you need to figure out which form is currently in view, and when transitions between forms happen.

Fortunately jQuery Mobile provides us the two facilities we need:

  • The ui-page-active CSS class gets applied to the .page element that is currently in view.
  • The pageshow event gets triggered on the document when a page transition has completed to change which page is in view.

Combine these two, and you can do something like this in your main javascript once for the whole document:

1
2
3
$(document).bind('pageshow', function() {
    $($('.page.ui-page-active form :input:visible')[0]).focus();
});

Now, after every page transition, if there is a form on the newly-visible page, the first visible input element automatically receives focus. This works across AJAX, non-AJAX, and BACK/FORWARD page transitions.

Revisited: Adding Filters to Stock Devise Controllers

| Comments

Six months ago, I wrote a quick blog post about adding custom filters to stock Devise controllers without subclassing all the Devise controllers. At the end of the post I noted that the prescribed method only worked in the production environment, and not in development.

Today I come to you with a solution that works in development as well as production. The basic mechanics are the same, but we’ll factor it slightly differently.

First, we’ll create a module in config/initializers/devise_filters.rb where we’ll implement a method to add all the filters to Devise that we want. We also need to make sure this module calls this method upon initialization so that our filters get added upon startup (important for the production environment).

devise_filters.rb View Gist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Put this somewhere it will get auto-loaded, like config/initializers
module DeviseFilters
  def self.add_filters
    # Example of adding a before_filter to all the Devise controller
    # actions we care about.
    [
      Devise::SessionsController,
      Devise::RegistrationsController,
      Devise::PasswordsController
    ].each do |controller|
      controller.before_filter :prepare_for_mobile
    end

    # Example of adding one selective before_filter.
    Devise::RegistrationsController.before_filter :check_invite_code, :only => :new
  end

  self.add_filters
end

At this point, we’re in the same place we left off back in August: we can add filters to Devise controller actions, but in development mode the second request reloads all the Devise classes and all our filters are gone.

To address this, we need to add a bit of code to the end of the initializer block in config/environments/development.rb like so:

1
2
3
4
5
6
7
8
MyApp::Application.configure do
  # ...the usual stuff ...

  # Stuff to do on each request
  config.to_prepare do
    DeviseFilters.add_filters
  end
end

This tells Rails to call your DeviseFilters.add_filters method before each new request in development mode, after the classes have been reloaded.

Enumerate Rails 3 Controller Filters

| Comments

There may come a time that you wish to programatically get a list of what before_filters, after_filters, and around_filters are set on a given controller class in Rails. In Rails 2, there was a filter_chain method on ActionController::Base that you could use to do this. That method is gone in Rails 3 in favor of something much more magical.

One reason for wanting to do this is simply for debugging. Sometimes you just need to sanity check that filters are being applied in the order you think they are. Especially when they’re being added dynamically by various plugins.

In Rails 3, I find it convenient to add a few utility methods to ApplicationController that list out the symbol names of all the filters on any given controller:

application_controller.rb View Gist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Add these methods to your ApplicationController. Then, any controller
# that inherits from it will have these methods and can programmatically
# determine what filters it has set.
class ApplicationController < ActionController::Base

  def self.filters(kind = nil)
    all_filters = _process_action_callbacks
    all_filters = all_filters.select{|f| f.kind == kind} if kind
    all_filters.map(&:filter)
  end

  def self.before_filters
    filters(:before)
  end

  def self.after_filters
    filters(:after)
  end

  def self.around_filters
    filters(:around)
  end

end

With that in hand, you can do something like this:

1
2
3
4
5
6
7
8
9
10
11
ree-1.8.7-2011.03 :002 > ap PostsController.before_filters
[
    [0] :verify_authenticity_token,
    [1] "_callback_before_1",
    [2] :set_geokit_domain,
    [3] :block_internet_explorer,
    [4] :add_authenticity_token,
    [5] :always_mobile,
    [6] :find_post,
    [7] :set_meta_tags
]

Off the Grid - Part Two

| Comments

It’s been almost two weeks since my first Off The Grid post, so I figured I’d report back on how it’s been going.

The bottom line is that I really like not being constantly distracted by growl notifications, iPhone push notifications, and little beeps vying for my attention. The biggest issue I had with constant communication connectivity was these concentration-killers. By turning off growl and push notifications, shutting down all social networking apps, and setting pre-defined times to check all these channels, I freed my mind up to focus on being creative for longer spurts.

My biggest concern about this experiment was that I wouldn’t be able to resist checking my email, Yammer, Facebook, Twitter, Google Reader, etc. every five minutes for fear of missing something time-sensitive. It turns out that was not the problem for me I thought it would be. It seems I’m quite happy ignoring everybody for extended periods of time. Knowing that I’ll be checking in regularly seems to be enough to relieve any subconscious concern that I’ll miss something when I don’t have notifications interrupting me.

What about those times someone needs to get ahold of me urgently? I think by not responding immediately to every email, the people around me quickly adjust their expectations. If they need to get ahold of me promptly, they use a more immediate communication channel – like text messaging.

I think I’ll continue in this mode. This seems like a good first step to a personal goal I made for Q1 2012: to be fluidly practicing the art of “zero inbox” by April 1. More on that later…

Inspiration Is Perishable

| Comments

rework

I woke up inspired to build something new this morning. I also woke up with this phrase echoing through my head: “Inspiration has a shelf life”. I laid in bed staring at the ceiling reciting to myself, “If you’re inspired now, do it now. Otherwise, it won’t ever happen.”

One of the most memorable chapters of the book Rework, by Jason Fried and David Heinemeier-Hansson, was its final one: Inspiration is Perishable. It’s main point was that it is not enough to have a good idea; you have to act when inspiration strikes.

Fix Rails Mishandling of HTTP Accept Header

| Comments

There are two Rails issues in its handling of the HTTP Accept header which cause spurious ActionView::MissingTemplate exceptions. This can be annoying when you are receiving emails on these via Airbrake, especially given that most of these come from web spiders. I am encountering this on Rails 3.0.7. One of these is fixed in a later version of Rails, but for other reasons I can’t upgrade right now. The other bug is still present in Rails 3.2 and in master at the time of this writing.

I have worked up a gist with monkey-patches that fix both issues:

https://gist.github.com/1754727

Read on to learn more about these issues and how my patches work…

Off the Grid

| Comments

Tomorrow I am conducting an experiment: I am going off the grid for a day.

Well, not really. But I do have a plan for taming the distractions of the internet. I am going to turn off all push notifications on my phone and all growl notifications on my desktop. I am going to keep my email client closed, shut down the Twitter app, the Yammer app, and avoid opening Facebook in my browser and phone. Maybe I’ll allow Google+ because it’s quieter in there than it is in my office with the door shut. My instant messenger client will be set to “do not disturb”.

I will check email, Twitter, Facebook, and Yammer at a few specific intervals:

  1. First thing in the morning.
  2. Around lunchtime.
  3. At the end of the day.
  4. During routine “meditation” (You know what I mean).

Feel free to contact me by any of the means you normally use. Just don’t expect me to respond until I do so on my schedule. If you need to contact me for something that is important and urgent, you can call me or text message me.

If you need to contact me for something that is time-sensitive, but not necessarily important, instant messenger or text message is a great way to get ahold of me. I may not respond promptly on IM, because I will have growl notifications turned off.

If this feels right, maybe I’ll extend the experiment for a few days…

UPDATED 2/13/2012: Read my follow up two weeks later, Off The Grid - Part Two

Embedded Tweet Tag for Jekyll

| Comments

A nice way to quote a tweet in your blog post is to use Twitter’s Embedded Tweet feature. Not only does it provide a familiar Twitter style, it also provides features like being able to directly retweet, follow, etc., without leaving your page. For example:

If you use Octopress or Jekyll, you can easily embed tweets using the Jekyll Tweet Tag. All you need to do is download tweet_tag.rb and store it in your Jekyll plugins directory.

Using AddThis With jQuery Mobile

| Comments

Because of the way AddThis works, it can be tricky to use the AddThis sharing widget within sections of a page that are dynamically vloaded via AJAX. The main trick they suggest in their forum is to re-initialize the script after you’ve dynamically added or modified an AddThis widget. This can be done with a method like this:

1
2
3
4
if (window.addthis) {
    window.addthis = null;
}
$.getScript("http://s7.addthis.com/js/250/addthis_widget.js#domready=1");

Now…when you’re using jQuery Mobile, you are very likely loading each page via AJAX instead of a full page request. This is the default behavior. Say you have a series of photos, and each click of a NEXT or PREV button slides in the next/prev photo in a series, as a full page dislay with AddThis buttons. You will need to reload AddThis every time a new page comes in to view.