module AbPanel module ControllerAdditions extend ActiveSupport::Concern # Track a single variable # # Example: # track_variable :name, value def track_variable(name, value) ab_panel_options[name.to_sym] = value end # Track multiple variables at once. # # Example: # track_variables { foo: 'bar', ping: 'pong'} def track_variables(variables={}) variables.each do |key, val| track_variable key, val end end # This sets a unique id for this user. # # You could override this in your ApplicationController to use your # own implementation, e.g.: # # `current_user.id` for logged in users. def ab_panel_id session['ab_panel_id'] ||= (0..4).map { |i| i.even? ? ('A'..'Z').to_a[rand(26)] : rand(10) }.join end # Sets the environment hash for every request. # # Experiment conditions and unique user id are preserved # in the user's session. # # You could override this to match your own env. def ab_panel_env { 'REMOTE_ADDR' => request['REMOTE_ADDR'], 'HTTP_X_FORWARDED_FOR' => request['HTTP_X_FORWARDED_FOR'], 'rack.session' => request['rack.session'], 'rails.env' => Rails.env, 'ip' => request.remote_ip, } end def ab_panel_options @ab_panel_options ||= {} end module ClassMethods # Initializes AbPanel's environment. # # Typically, this would go in the ApplicationController. # # class ApplicationController < ActionController::Base # initialize_ab_panel! # end # # This makes sure an ab_panel session is re-initialized on every # request. Experiment conditions and unique user id are preserved # in the user's session. def initialize_ab_panel!(options={}) self.before_filter(options.slice(:only, :except)) do |controller| # Persist the conditions. AbPanel.conditions = controller.session['ab_panel_conditions'] controller.session['ab_panel_conditions'] = AbPanel.conditions { 'ab_panel_id' => controller.ab_panel_id }.merge(controller.ab_panel_env).each do |key, val| AbPanel.env_set key, val end end end # Track controller actions visits. # # name - The name of the event in Mixpanel. # properties - The properties to be associated with the event. # # Example: # # track_action '[visits] Booking form', { :only => :book_now, :course => :id } # # This will track the event with the given name on CoursesController#book_now # and assign an options hash: # # { 'course_id' => @course.id } def track_action(name, options={}) self.after_filter(options.slice(:only, :except)) do |controller| properties = options.slice! :only, :except options = { distinct_id: controller.ab_panel_id, ip: controller.request.remote_ip, time: Time.now.utc, } AbPanel.experiments.each do |exp| options[exp] = AbPanel.conditions.send(exp).condition rescue nil end properties.each do |key, val| if controller.respond_to?(key) inst = controller.send(key) elsif controller.instance_variable_defined?("@#{key}") inst = controller.instance_variable_get("@#{key}") else options[key] = val next end val = *val val.each do |m| options["#{key}_#{m}"] = inst.send(m) end end AbPanel.identify(controller.ab_panel_id) AbPanel.track name, options.merge(controller.ab_panel_options) controller.session['mixpanel_events'] ||= AbPanel.env['rack.session']['mixpanel_events'] rescue [] end end end end end if defined? ActionController::Base ActionController::Base.class_eval do include AbPanel::ControllerAdditions end end