Skip to content

Instantly share code, notes, and snippets.

@chrisdavies
Created January 18, 2013 22:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisdavies/4569299 to your computer and use it in GitHub Desktop.
Save chrisdavies/4569299 to your computer and use it in GitHub Desktop.
In Rails (3.2.8), I needed to allow different browser tabs to behave as if they were different apps (my rails app will be embedded in an iframe in various apps). For a variety of reasons, I couldn't track apps via sub-domains. Cookies failed, because browser tabs all share the same cookies, so there were race-conditions and other buggery. My sol…
require 'addressable/uri'
module MyApp
# This rack-filter gets run before any urls are processed by the routing
# subsystem, enabling us to extract the app_id query parameter and cache it for
# the duration of the current request thread.
class ClientIdManager
def initialize(app)
@app = app
end
def call(env)
url = Addressable::URI.parse(env['REQUEST_URI'])
if (url.query_values && url.query_values.has_key?('app_id'))
ClientIdProvider.app_id = url.query_values['app_id']
else
ClientIdProvider.app_id = '-1'
end
@app.call(env)
end
end
end
module MyApp
# This provides convenient access to the current app_id
# It also (via to_s) is able to provide said app_id to
# external classes which are configured in application
# initialization
class ClientIdProvider
def self.app_id
Thread.current['app_id']
end
def self.app_id=(val)
Thread.current['app_id'] = val
end
def to_s
ClientIdProvider.app_id
end
end
end
# In your application.rb
# Ensure that app_id is persisted in all urls generated from this app
Rails.application.routes.default_url_options = { 'app_id' => MyApp::ClientIdProvider.new }
# Add our filter to the rack middleware
config.middleware.use 'MyApp::ClientIdManager'
# In your omniauth configuration:
# Pass the app_id to external providers (for Google, this is in the 'state' parameter)
# Be sure to set provider_ignores_state: true
# This prevents an annoying issue where specifying state makes
# calls to Google fail.
config.omniauth :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], { state: MyApp::ClientIdProvider.new, provider_ignores_state: true, scope: 'userinfo.email,userinfo.profile', access_type: 'online', approval_prompt: ''}
# In your omniauth controller processing methods
# Be sure to set the app_id (or whatever param you want to persist)
# When it comes back from external omniauth calls.
# Example Omniauth callback controller Google processing function:
def process_google_response
MyApp::ClientIdProvider.app_id = params['state']
# ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment