Skip to content

Instantly share code, notes, and snippets.

@critzjm
Created June 13, 2012 16:39
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 critzjm/2925182 to your computer and use it in GitHub Desktop.
Save critzjm/2925182 to your computer and use it in GitHub Desktop.
# This model represents a User of the system. The main User functionality is declared
# using the `authable_user` command which is defined as a part of the Challah gem.
#
# Users can be registered with a username and password (admin only) or directly on the site
# from Facebook. If a user was registered with Facebook, they will have a `fb_identifier`
# and a `fb_access_token` value. If these values are present, the user will not be able to log
# in with a username/password combination.
#
# ## Columns
# * :first_name - First name
# * :last_name - Last name
# * :username - Username (usually email address)
# * :email - Email address
# * :crypted_password - Encrypted password hash
# * :persistence_token - What gets stored in the cookie
# * :api_key - Unique access token for the user
# * :role_id - Id of the role this user belongs to
# * :last_session_at - Timestamp of the user's most recent session
# * :last_session_ip - IP address of the user's most recent session
# * :session_count - Number of sessions
# * :failed_auth_count - Number of times user has failed to authenticate
# * :created_by - Id of the user who created this user
# * :updated_by - Id of the user who last updated this user
# * :created_at - Timestamp of when the user was created
# * :updated_at - Timestamp
# * :active - True if the user is a valid, active user
# * :fb_identifier - Facebook user id
# * :fb_access_token - Facebook access token
# * :registered - True if the user is currently
# * :registered_at - Timestamp of when the user was registered
# * :location - String of the user's location
# * :locale - Locale (e.g. 'en-US')
# * :gender - Gender
# * :primary_discipline - Description of career field
# * :timezone - Timezone of the user
# * :linked_in - URL for the user's LinkedIn profile
# * :twitter - Twitter username (without the @)
# * :birthdate - Date of birth
# * :bio - Short bio
# * :mobile - Mobile phone number
# * :carrier_id - Id of the carrier
# * :updates - Boolean value to opt in to newsletter
# * :anonymous - Boolean indicating whether user wants to be anonymous
# * :clown_mode - Boolean indicating whether user has "clown mode" activated (nothing submitted is posted or displayed)
#
require 'badge_collection'
class User < ActiveRecord::Base
# Challah set up
################################################################
# Set up the user from Challah
#
# Provides basic validations and associations with roles and permissions.
#
# See http://rubydoc.info/gems/challah for more information about this.
authable_user
# Override the attributes that are protected by Challah to include these that a user can't
# updated themselves.
#
# Anywhere a user can update their own information, call the user#update_account_attributes
# method instead of user#update_attributes to automatically remove these protected attributes.
#
# This ensures that someone can't update their own user role, api key, fb_identifier, etc...
protect_attributes :fb_identifier, :fb_access_token, :registered
# Whitelist user-updateable fields
attr_accessible :anonymous, :bio, :gender, :linked_in, :locale, :location, :timezone, :twitter, :updates, :user_discipline_id
# Validations
################################################################
validates :fb_access_token, :presence => { :if => :facebook? }
validates :fb_identifier, :presence => { :if => :facebook? }
# Associations
################################################################
has_many :activities
has_many :ballots
has_many :ideas, :foreign_key => 'created_by',
:order => 'ideas.created_at DESC'
has_many :invites, :dependent => :destroy,
:order => 'invites.created_at DESC'
has_many :links, :as => :linkable,
:dependent => :destroy,
:order => 'links.created_at ASC'
has_many :owned_briefs, :class_name => 'Brief',
:foreign_key => 'owned_by'
has_many :employments, :class_name => 'UserEmployment',
:dependent => :destroy
has_many :involvements
has_many :briefs, :through => :involvements
belongs_to :level
belongs_to :discipline, :foreign_key => 'user_discipline_id',
:class_name => 'UserDiscipline'
accepts_nested_attributes_for :links,
:reject_if => :all_blank,
:allow_destroy => true
accepts_nested_attributes_for :employments,
:reject_if => :all_blank,
:allow_destroy => true
acts_as_linkable
# Scopes
################################################################
default_scope order('"users"."first_name", "users"."last_name"')
# Returns a list of all Facebook users
scope :facebook, where(:facebook => true)
# Returns a list of all users that are not signed up with Facebook
scope :not_facebook, where(:facebook => false)
# Returns a list of all registered users
scope :registered, where(:registered => true)
# Callbacks
################################################################
before_save :log_activity
# Serialization
################################################################
serialize_with :only => [ :id ], :methods => [ :avatar_url, :points, :name ]
# Public Methods
################################################################
# Get a stream of the public activities of this user
def activity_stream
@activity_stream ||= self.activities.unrestricted
end
# Add the given number of points to this user's point total. The user must already exist
# and have a valid `redis_key`. If the user does not have any points yet, they will start
# with zeor points and this number will be added to them.
#
# Instead of passing in a number of points, you can also pass in a Symbol to pull from a
# `PointTemplate` instance. This is helpful so we don't have to hardcode point values often
# and we can just pull from template values.
def add_points(points_or_template_key = 1)
return 0 unless redis_key
# Allow points to be set from a template (gives us an easy way to change point values in the app)
# Or, if no Symbol is passed, just increment by the given number of points.
points_to_add = Symbol === points_or_template_key ? PointTemplate[points_or_template_key] : points_or_template_key
points_to_add = points_to_add.to_i
# If the value given is not greater than zero, just return the current number of points and
# do not continue.
return self.points if points_to_add <= 0
# update the updated_at attribute to release any caches for this user
self.touch
@points = REDIS.incrby(redis_key(:points), points_to_add).to_i
check_for_level_change
@points
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment