devise_referable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +81 -0
  5. data/Rakefile +54 -0
  6. data/VERSION +1 -0
  7. data/app/controllers/referrals_controller.rb +12 -0
  8. data/app/models/referral.rb +38 -0
  9. data/devise_referable.gemspec +117 -0
  10. data/init.rb +1 -0
  11. data/lib/devise/hooks/referable.rb +13 -0
  12. data/lib/devise_referable/model.rb +47 -0
  13. data/lib/devise_referable/routes.rb +12 -0
  14. data/lib/devise_referable.rb +12 -0
  15. data/rails/init.rb +1 -0
  16. data/test/integration/referable_test.rb +59 -0
  17. data/test/integration_tests_helper.rb +35 -0
  18. data/test/model_tests_helper.rb +64 -0
  19. data/test/models/referral_test.rb +40 -0
  20. data/test/models_test.rb +31 -0
  21. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  22. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  23. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  24. data/test/rails_app/app/controllers/users_controller.rb +12 -0
  25. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  26. data/test/rails_app/app/models/blog.rb +3 -0
  27. data/test/rails_app/app/models/user.rb +4 -0
  28. data/test/rails_app/app/views/home/index.html.erb +1 -0
  29. data/test/rails_app/config/boot.rb +110 -0
  30. data/test/rails_app/config/database.yml +22 -0
  31. data/test/rails_app/config/environment.rb +44 -0
  32. data/test/rails_app/config/environments/development.rb +17 -0
  33. data/test/rails_app/config/environments/production.rb +28 -0
  34. data/test/rails_app/config/environments/test.rb +28 -0
  35. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  36. data/test/rails_app/config/initializers/devise.rb +76 -0
  37. data/test/rails_app/config/initializers/inflections.rb +2 -0
  38. data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
  39. data/test/rails_app/config/initializers/session_store.rb +15 -0
  40. data/test/rails_app/config/routes.rb +4 -0
  41. data/test/rails_app/vendor/plugins/devise_referable/init.rb +1 -0
  42. data/test/routes_test.rb +21 -0
  43. data/test/test_helper.rb +66 -0
  44. metadata +167 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ test/rails_app/log
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Matt Van Horn, derived from work done by Sergio Cambra
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ = devise_referable
2
+
3
+ It adds support to devise[http://github.com/plataformatec/devise] for tracking
4
+ users that were sent by referrers modeled as other classes in your app.
5
+
6
+ == Installation
7
+
8
+ All gems are on gemcutter, so you need to add gemcutter to your sources if you haven’t yet:
9
+
10
+ sudo gem sources -a http://gemcutter.org/
11
+
12
+ Install devise_referable gem, it should install dependencies (such as devise and warden):
13
+
14
+ sudo gem install devise_referable
15
+
16
+ Configure devise_referable inside your app (and warden and devise if you weren't using them):
17
+
18
+ config.gem 'warden'
19
+ config.gem 'devise'
20
+ config.gem 'devise_referable'
21
+
22
+ == Basic Usage
23
+
24
+ Follow the walkthrough for devise with the following modifications.
25
+
26
+ Create a migration for the referrals table:
27
+
28
+ create_table :referrals, :force => true do |t|
29
+ t.integer :referrer_id
30
+ t.string :referrer_type
31
+ t.integer :recipient_id
32
+ t.string :referral_token
33
+ t.datetime :registered_at
34
+ t.timestamps
35
+ end
36
+
37
+ Add a referrer_token column to your referrer classes.
38
+
39
+ add_column :table_name1, :referrer_token, :string
40
+ add_column :table_name2, :referrer_token, :string
41
+
42
+ Add indexes if you want
43
+ add_index :referrals, :referral_token
44
+ add_index :table_name1, :referrer_token
45
+ add_index :table_name2, :referrer_token
46
+
47
+
48
+ Add :referable to the devise line in your model:
49
+
50
+ class User < ActiveRecord::Base
51
+ devise ..., :referable
52
+ end
53
+
54
+ If you are using devise :all, you can add :referable to config.all in devise initializer:
55
+ Devise.setup do |config|
56
+ ...
57
+ config.all = [..., :referable]
58
+ ...
59
+ end
60
+
61
+ == Model configuration
62
+
63
+ DeviseReferable adds a new configuration option, :referral_types. It should be
64
+ an array of classes which can act as a referrer
65
+
66
+
67
+ == Note on Patches/Pull Requests
68
+
69
+ * Fork the project.
70
+ * Make your feature addition or bug fix.
71
+ * Add tests for it. This is important so I don't break it in a
72
+ future version unintentionally.
73
+ * Commit, do not mess with rakefile, version, or history.
74
+ (if you want to have your own version, that is fine but
75
+ bump version in a commit by itself I can ignore when I pull)
76
+ * Send me a pull request. Bonus points for topic branches.
77
+
78
+ == Copyright
79
+
80
+ Copyright (c) 2010 Matt Van Horn, based on work by {Sergio Cambra}[http://github.com/scambra/devise_invitable].
81
+ See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "devise_referable"
8
+ gem.summary = %Q{An allows referral tracking for devise}
9
+ gem.description = %Q{It tracks the referring entity via cookie, and creates a record when user registers.}
10
+ gem.email = "mattvanhorn@gmail.com"
11
+ gem.homepage = "http://github.com/mattvanhorn/devise_referable"
12
+ gem.authors = ["Matt Van Horn, based on work by Sergio Cambra"]
13
+ gem.add_development_dependency 'mocha'
14
+ gem.add_development_dependency 'webrat'
15
+ gem.add_dependency 'devise', '~> 1.0.0'
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/*_test.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "devise_referable #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,12 @@
1
+ class ReferralsController < ApplicationController
2
+
3
+ def create
4
+ unless user_signed_in?
5
+ @referral = Referral.from_token(params[:referrer_token])
6
+ session[:referral_token] = @referral.referral_token if @referral
7
+ end
8
+ redirect_to "/#{params[:path].join('/')}"
9
+ end
10
+
11
+ end
12
+
@@ -0,0 +1,38 @@
1
+ require 'devise/hooks/referable'
2
+
3
+ class Referral < ActiveRecord::Base
4
+ belongs_to :referrer, :polymorphic => true
5
+ belongs_to :recipient, :class_name => 'User'
6
+
7
+ before_create :generate_token
8
+
9
+ class << self
10
+ def referrer_types
11
+ User.referrer_types
12
+ end
13
+
14
+ def lookup_referrer(token)
15
+ unless token.blank?
16
+ referrer_types.map{ |type| type.to_s.classify.constantize }.each do |klass|
17
+ ref = klass.find_by_referrer_token(token)
18
+ return ref unless ref.nil?
19
+ end
20
+ end
21
+ return nil
22
+ end
23
+
24
+ def from_token(token)
25
+ sender = lookup_referrer(token)
26
+ if sender
27
+ Referral.create do |ref|
28
+ ref.referrer = sender
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def generate_token
35
+ self.referral_token ||= Devise.friendly_token
36
+ end
37
+
38
+ end
@@ -0,0 +1,117 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{devise_referable}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Matt Van Horn, based on work by Sergio Cambra"]
12
+ s.date = %q{2010-03-16}
13
+ s.description = %q{It tracks the referring entity via cookie, and creates a record when user registers.}
14
+ s.email = %q{mattvanhorn@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "app/controllers/referrals_controller.rb",
27
+ "app/models/referral.rb",
28
+ "devise_referable.gemspec",
29
+ "init.rb",
30
+ "lib/devise/hooks/referable.rb",
31
+ "lib/devise_referable.rb",
32
+ "lib/devise_referable/model.rb",
33
+ "lib/devise_referable/routes.rb",
34
+ "rails/init.rb",
35
+ "test/integration/referable_test.rb",
36
+ "test/integration_tests_helper.rb",
37
+ "test/model_tests_helper.rb",
38
+ "test/models/referral_test.rb",
39
+ "test/models_test.rb",
40
+ "test/rails_app/app/controllers/admins_controller.rb",
41
+ "test/rails_app/app/controllers/application_controller.rb",
42
+ "test/rails_app/app/controllers/home_controller.rb",
43
+ "test/rails_app/app/controllers/users_controller.rb",
44
+ "test/rails_app/app/helpers/application_helper.rb",
45
+ "test/rails_app/app/models/blog.rb",
46
+ "test/rails_app/app/models/user.rb",
47
+ "test/rails_app/app/views/home/index.html.erb",
48
+ "test/rails_app/config/boot.rb",
49
+ "test/rails_app/config/database.yml",
50
+ "test/rails_app/config/environment.rb",
51
+ "test/rails_app/config/environments/development.rb",
52
+ "test/rails_app/config/environments/production.rb",
53
+ "test/rails_app/config/environments/test.rb",
54
+ "test/rails_app/config/initializers/backtrace_silencers.rb",
55
+ "test/rails_app/config/initializers/devise.rb",
56
+ "test/rails_app/config/initializers/inflections.rb",
57
+ "test/rails_app/config/initializers/new_rails_defaults.rb",
58
+ "test/rails_app/config/initializers/session_store.rb",
59
+ "test/rails_app/config/routes.rb",
60
+ "test/rails_app/vendor/plugins/devise_referable/init.rb",
61
+ "test/routes_test.rb",
62
+ "test/test_helper.rb"
63
+ ]
64
+ s.homepage = %q{http://github.com/mattvanhorn/devise_referable}
65
+ s.rdoc_options = ["--charset=UTF-8"]
66
+ s.require_paths = ["lib"]
67
+ s.rubygems_version = %q{1.3.6}
68
+ s.summary = %q{An allows referral tracking for devise}
69
+ s.test_files = [
70
+ "test/integration/referable_test.rb",
71
+ "test/integration_tests_helper.rb",
72
+ "test/model_tests_helper.rb",
73
+ "test/models/referral_test.rb",
74
+ "test/models_test.rb",
75
+ "test/rails_app/app/controllers/admins_controller.rb",
76
+ "test/rails_app/app/controllers/application_controller.rb",
77
+ "test/rails_app/app/controllers/home_controller.rb",
78
+ "test/rails_app/app/controllers/users_controller.rb",
79
+ "test/rails_app/app/helpers/application_helper.rb",
80
+ "test/rails_app/app/models/blog.rb",
81
+ "test/rails_app/app/models/user.rb",
82
+ "test/rails_app/config/boot.rb",
83
+ "test/rails_app/config/environment.rb",
84
+ "test/rails_app/config/environments/development.rb",
85
+ "test/rails_app/config/environments/production.rb",
86
+ "test/rails_app/config/environments/test.rb",
87
+ "test/rails_app/config/initializers/backtrace_silencers.rb",
88
+ "test/rails_app/config/initializers/devise.rb",
89
+ "test/rails_app/config/initializers/inflections.rb",
90
+ "test/rails_app/config/initializers/new_rails_defaults.rb",
91
+ "test/rails_app/config/initializers/session_store.rb",
92
+ "test/rails_app/config/routes.rb",
93
+ "test/rails_app/vendor/plugins/devise_referable/init.rb",
94
+ "test/routes_test.rb",
95
+ "test/test_helper.rb"
96
+ ]
97
+
98
+ if s.respond_to? :specification_version then
99
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
100
+ s.specification_version = 3
101
+
102
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
103
+ s.add_development_dependency(%q<mocha>, [">= 0"])
104
+ s.add_development_dependency(%q<webrat>, [">= 0"])
105
+ s.add_runtime_dependency(%q<devise>, ["~> 1.0.0"])
106
+ else
107
+ s.add_dependency(%q<mocha>, [">= 0"])
108
+ s.add_dependency(%q<webrat>, [">= 0"])
109
+ s.add_dependency(%q<devise>, ["~> 1.0.0"])
110
+ end
111
+ else
112
+ s.add_dependency(%q<mocha>, [">= 0"])
113
+ s.add_dependency(%q<webrat>, [">= 0"])
114
+ s.add_dependency(%q<devise>, ["~> 1.0.0"])
115
+ end
116
+ end
117
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rails/init'
@@ -0,0 +1,13 @@
1
+ # After a user is set, we check to make sure that if they were referred, the
2
+ # referral is updated with the user's id.
3
+ # This will generally happen on registration, but could possibly happen on login
4
+ # in other circumstances where a user was existing in a legacy db for example.
5
+
6
+ Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
7
+ token = warden.env['rack.session'][:referral_token]
8
+ scope = options[:scope]
9
+ if record.respond_to?(:referral) && record.referral.nil? && warden.authenticated?(scope) && token
10
+ record.update_referral(token) if record.respond_to?(:update_referral)
11
+ warden.env['rack.session'][:referral_token] = nil
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ module Devise
2
+ module Models
3
+ # Referable tracks users that arrive at your site via an affiliate link.
4
+ # Currently this is hardcoded as /ref/:referrer_token/path/to/destination
5
+ # TODO: make url configurable
6
+ #
7
+ # Classes that act as referrers are specified in the config, and must
8
+ # have a referrer_token column in the database.
9
+ # TODO: make column name configurable
10
+ #
11
+ # When a visitor arrives at the site via the referral_landing_path, the following things happen:
12
+ # - The referrer is looked up, by doing finds against the referrer_types in order.
13
+ # - If found, a referral record is created with a unique referral_token.
14
+ # - The referral_token is also stored in the session
15
+ # - The visitor is then redirected to the path appended to the referral_landing_path (i.e. /path/to/destination above)
16
+ # - If no path is given, they're redirected to the root path.
17
+ # - If the visitor registers during the session, the referral record is updated with the new user id, and the session token is cleared.
18
+ #
19
+ # Configuration:
20
+ #
21
+ # referrer_types: an array of symbols for classes that can refer users. i.e. [:blog, :customer, :user]
22
+ #
23
+ module Referable
24
+
25
+ def self.included(base)
26
+ base.class_eval do
27
+ has_one :referral, :foreign_key => :recipient_id
28
+ extend ClassMethods
29
+ end
30
+ end
31
+
32
+ def update_referral(token)
33
+ referral = Referral.find_by_referral_token(token)
34
+ if referral
35
+ referral.update_attributes( :recipient_id => self.id,
36
+ :registered_at => self.created_at )
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ module ClassMethods
43
+ Devise::Models.config(self, :referrer_types)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ module DeviseReferable
2
+ module Routes
3
+
4
+ protected
5
+
6
+ def referable(routes, mapping)
7
+ send(:"referral_landing", 'ref/:referrer_token/*path', {:controller => 'referrals', :action => 'create', :conditions => { :method => :get }})
8
+ end
9
+ end
10
+ end
11
+
12
+ ActionController::Routing::RouteSet::Mapper.send :include, DeviseReferable::Routes
@@ -0,0 +1,12 @@
1
+ Devise.module_eval do
2
+ # list of classes that can act as referrer.
3
+ mattr_accessor :referrer_types
4
+ @@referrer_types = []
5
+ end
6
+ Devise.add_module :referable, :controller => :referrals, :model => 'devise_referable/model'
7
+
8
+ module DeviseReferable; end
9
+
10
+ require File.join(File.dirname(__FILE__), '..', 'app', 'models', 'referral')
11
+
12
+ require 'devise_referable/routes'
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'devise_referable'
@@ -0,0 +1,59 @@
1
+ require 'test/test_helper'
2
+ require 'test/integration_tests_helper'
3
+
4
+ class ReferralTest < ActionController::IntegrationTest
5
+
6
+ def setup
7
+ @blog = Blog.create!(:name => 'Referrer', :referrer_token => 'abc123')
8
+ end
9
+
10
+ test 'new users should get referral records' do
11
+ assert_equal 0, Referral.count
12
+ visit referral_landing_path(:referrer_token => 'abc123')
13
+ assert :success
14
+ assert_equal 1, Referral.count
15
+ assert_not_nil session[:referral_token]
16
+
17
+ visit new_user_registration_path
18
+ assert :success
19
+
20
+ fill_in 'email', :with => 'new_user@test.com'
21
+ fill_in 'password', :with => 'new_user123'
22
+ fill_in 'password confirmation', :with => 'new_user123'
23
+ click_button 'Sign up'
24
+
25
+ user = User.last :order => "id"
26
+
27
+ assert user.referral.referrer == @blog
28
+ end
29
+
30
+ test 'existing users should not get referral records' do
31
+ assert_equal 0, Referral.count
32
+
33
+ visit new_user_registration_path
34
+ assert :success
35
+
36
+ fill_in 'email', :with => 'new_user@test.com'
37
+ fill_in 'password', :with => 'new_user123'
38
+ fill_in 'password confirmation', :with => 'new_user123'
39
+ click_button 'Sign up'
40
+ assert :success
41
+
42
+ visit '/ref/abc123'
43
+ assert :success
44
+
45
+ user = User.last :order => "id"
46
+ assert_equal 0, Referral.count
47
+ assert_nil user.referral
48
+ end
49
+
50
+ test 'referral lookup failures should be ignored' do
51
+ assert_equal 0, Referral.count
52
+ visit referral_landing_path(:referrer_token => 'bogus')
53
+ assert :success
54
+
55
+ assert_equal 0, Referral.count
56
+ assert_nil session[:referral_token]
57
+ end
58
+
59
+ end
@@ -0,0 +1,35 @@
1
+ class ActionController::IntegrationTest
2
+
3
+ def warden
4
+ request.env['warden']
5
+ end
6
+
7
+ def sign_in_as_user
8
+ Warden::Proxy.any_instance.stubs(:user).at_least_once.returns(User.new)
9
+ end
10
+
11
+ def create_user(accept_invitation = true)
12
+ user = User.new :email => 'newuser@test.com'
13
+ user.save(false)
14
+ user
15
+ end
16
+
17
+ # Fix assert_redirect_to in integration sessions because they don't take into
18
+ # account Middleware redirects.
19
+ #
20
+ def assert_redirected_to(url)
21
+ assert [301, 302].include?(@integration_session.status),
22
+ "Expected status to be 301 or 302, got #{@integration_session.status}"
23
+
24
+ url = prepend_host(url)
25
+ location = prepend_host(@integration_session.headers["Location"])
26
+ assert_equal url, location
27
+ end
28
+
29
+ protected
30
+
31
+ def prepend_host(url)
32
+ url = "http://#{request.host}#{url}" if url[0] == ?/
33
+ url
34
+ end
35
+ end
@@ -0,0 +1,64 @@
1
+ class ActiveSupport::TestCase
2
+ def setup_mailer
3
+ ActionMailer::Base.deliveries = []
4
+ end
5
+
6
+ def store_translations(locale, translations, &block)
7
+ begin
8
+ I18n.backend.store_translations locale, translations
9
+ yield
10
+ ensure
11
+ I18n.reload!
12
+ end
13
+ end
14
+
15
+ # Helpers for creating new users
16
+ #
17
+ def generate_unique_email
18
+ @@email_count ||= 0
19
+ @@email_count += 1
20
+ "test#{@@email_count}@email.com"
21
+ end
22
+
23
+ def valid_attributes(attributes={})
24
+ { :email => generate_unique_email,
25
+ :password => '123456',
26
+ :password_confirmation => '123456' }.update(attributes)
27
+ end
28
+
29
+ def new_user(attributes={})
30
+ User.new(valid_attributes(attributes))
31
+ end
32
+
33
+ def new_referral(attributes={})
34
+ Referral.new(attributes)
35
+ end
36
+
37
+ def create_user(attributes={})
38
+ User.create!(valid_attributes(attributes))
39
+ end
40
+
41
+ # def create_user_with_invitation(invitation_token, attributes={})
42
+ # user = new_user({:password => nil, :password_confirmation => nil}.update(attributes))
43
+ # user.skip_confirmation!
44
+ # user.invitation_token = invitation_token
45
+ # user.invitation_sent_at = Time.now.utc
46
+ # user.save(false)
47
+ # user
48
+ # end
49
+
50
+ # Execute the block setting the given values and restoring old values after
51
+ # the block is executed.
52
+ def swap(object, new_values)
53
+ old_values = {}
54
+ new_values.each do |key, value|
55
+ old_values[key] = object.send key
56
+ object.send :"#{key}=", value
57
+ end
58
+ yield
59
+ ensure
60
+ old_values.each do |key, value|
61
+ object.send :"#{key}=", value
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/test_helper'
2
+ require 'test/model_tests_helper'
3
+
4
+ class ReferableTest < ActiveSupport::TestCase
5
+ def setup
6
+ end
7
+
8
+ test 'should look up referrer' do
9
+ blog = mock()
10
+ Blog.expects(:find_by_referrer_token).with('abc123').returns(blog)
11
+ assert Referral.lookup_referrer('abc123') == blog
12
+ end
13
+
14
+ test 'should return nil if no referrer is found' do
15
+ Blog.expects(:find_by_referrer_token).with('abc123').returns(nil)
16
+ assert_nil Referral.lookup_referrer('abc123')
17
+ end
18
+
19
+ test 'should create referral from token' do
20
+ Blog.expects(:find_by_referrer_token).with('abc123').returns(create_user) # I just need an AR obj here to avoid massive stubbing.
21
+ # Should be a blog not a user.
22
+ result = Referral.from_token('abc123')
23
+ assert result.is_a?( Referral)
24
+ assert_not_nil result.referral_token
25
+ assert_not_nil result.referrer_id
26
+ assert_not_nil result.referrer_type
27
+ assert !result.new_record?
28
+ end
29
+
30
+ test 'should never generate the same referral token for different users' do
31
+ referral_tokens = []
32
+ 10.times do
33
+ ref = new_referral(:referrer_id => 1, :referrer_type => 'Publisher')
34
+ token = ref.generate_token
35
+ assert !referral_tokens.include?(token)
36
+ referral_tokens << token
37
+ end
38
+ end
39
+
40
+ end