Skip to content

Instantly share code, notes, and snippets.

@superp
Last active October 30, 2015 09:41
Show Gist options
  • Save superp/b0458872ce0e202c7c6f to your computer and use it in GitHub Desktop.
Save superp/b0458872ce0e202c7c6f to your computer and use it in GitHub Desktop.
Invite module
class Account < ActiveRecord::Base
include SimpleTree
include Invitation
end
require 'securerandom'
module Invitation
extend ActiveSupport::Concern
included do
before_create :generate_invitation_token
define_model_callbacks :invite, :only => [:after, :before]
scope :inviter, lambda { |token| where(:invitation_token => token) }
end
module ClassMethods
# Generate a token checking if one does not already exist in the database.
def invitation_token
generate_token(:invitation_token)
end
# Generate a token by looping and ensuring does not already exist.
def generate_token(column, limit=8)
loop do
token = ::SecureRandom.base64(16).tr('+/=lIO0', 'pqrsxyz').slice(0, limit)
break token unless where({ column => token }).exists?
end
end
def find_invite!(token)
invitor = inviter(token).first
raise ActiveRecord::RecordNotFound, "Invitor by #{token} not found" if invitor.nil?
invitor
end
end
# Join account by set parent record
def invite(account)
if account && account.parent.nil? && account != self && !account.children.where(:id => id).exists?
run_callbacks :invite do
account.parent_id = self.id
account.save(:validate => false)
end
end
!account.nil? && account.parent == self
end
protected
# Generates a new random token for invitation, and stores the time
# this token is being generated
def generate_invitation_token
self.invitation_token = self.class.invitation_token
end
end
class InvitationsController < ApplicationController
before_filter :find_invitor
def show
if account_signed_in?
@invitor.invite(current_account)
redirect_to account_dashboard_path
else
cookies[:invite] = @invitor.invitation_token
redirect_to root_path
end
end
protected
def find_invitor
@invitor = Writer.find_invite!(params[:id])
end
end
class SessionsController < ActionController::Metal
def create
...
redirect_to account_callback_path(resource)
end
protected
def account_callback_path(resource)
...
if inviter = find_inviter
"/invitations/#{inviter.invitation_token}"
else
...
end
end
def find_inviter
token = request.cookie_jar[:invite] || params['invite'] || request.env['omniauth.params']['invite']
token.blank? ? nil : Account.find_invite(token)
end
end
module SimpleTree
extend ActiveSupport::Concern
included do
belongs_to :parent,
:class_name => self.base_class.to_s,
:foreign_key => :parent_id,
:inverse_of => :children,
:counter_cache => :children_count
has_many :children,
:class_name => self.base_class.to_s,
:foreign_key => :parent_id,
:inverse_of => :parent
scope :roots, lambda { where(:parent_id => nil) }
scope :with_children, lambda { where("#{quoted_table_name}.children_count > 0") }
end
def has_children?
!children_count.zero?
end
def root?
parent_id.nil?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment