Tuesday, July 03, 2007

Making Rails' session work with Facebook

When using Facebook and ActiveRecordStore for sessions in Rails, rails generates a new session for every request. The following is a quick solution to the problem. First change your application's session_key by adding the following to the bottom of environment.rb.
ActionController::Base.session_options['session_key'] = 'fb_sig_session_key'

Next, override ActiveRecordStore#initialize to by adding the following to the bottom of environment.rb

class CGI
class Session
class ActiveRecordStore
def initialize(session, option = nil)
session_id = session.session_id
unless @session = ActiveRecord::Base.silence { @@session_class.find_by_session_id(session_id) }
@session = @@session_class.new(:session_id => session_id, :data => {})
end
end
end
end
end

Then restart your server. Your session should now persist between requests and have the same id as fb_sig_session_key.

Wednesday, June 13, 2007

Changing form element names

Last night's facebook update is incompatible with the way the rails handles form parameters. "object[field_1]" becomes "object" => "Array" instead of "object" => {"field_1" => ...}. Until the issue is resolved, a simple fix is to tell rails to name forms using parentheses instead of brackets. Additionally, rails will need to parse parentheses in parameter keys as brackets. The following code does just that. To use, just slap it at the bottom of your environment.rb.

module ActionView
module Helpers
class InstanceTag
def tag_name
"#{@object_name}(#{@method_name})"
end

def tag_name_with_index(index)
"#{@object_name}(#{index})(#{@method_name})"
end
end
end
end

class CGIMethods
def self.parse_request_parameters(params)
parser = FormEncodedPairParser.new

params = params.dup
until params.empty?
for key, value in params
if key.blank?
params.delete key
elsif !key.include?('(') && !key.include?('[')
# much faster to test for the most common case first (GET)
# and avoid the call to build_deep_hash
parser.result[key] = get_typed_value(value[0])
params.delete key
elsif value.is_a?(Array)
parser.parse(key.tr('()', '[]'), get_typed_value(value.shift))
params.delete key if value.empty?
else
raise TypeError, "Expected array, found #{value.inspect}"
end
end
end
parser.result
end
end