MuckProfiles
Muck profiles adds profiles to muck users. This implements a photo for users as well as an easy way to add any number of properties to enable total customization of the user’s profile information including privacy settings.
Installation
Muck profile relies upon the muck-engine and muck-users gems as well as paperclip. Add the following lines to your Gemfile:
gem 'paperclip'
gem 'muck-engine'
gem 'muck-users'
gem 'muck-profiles'
gem 'geokit' # Only needed if you want to add location to your profiles. MuckProfiles uses geokit to determine a users
# location and to make it possible to find users that are within a given proximity.
Install the GeoKit Rails Plugin:
script/plugin install git://github.com/andre/geokit-rails.git
Be sure to get api keys from Google an Yahoo. Instructions for doing so can be found in config/initializers/geokit_config.rb after installing the plugin.
We recommend moving the keys into secrets.yml:
google_geo_key: 'some key' # API key for Google. Get it here: http://www.google.com/apis/maps/signup.html
yahoo_geo_key: 'some key' # API key for Yahoo. Get it here: http://developer.yahoo.com/faq/index.html#appid
Then change the lines in config/initializers/geokit_config.rb to:
Geokit::Geocoders::yahoo = Secrets.yahoo_geo_key
Geokit::Geocoders::google = Secrets.google_geo_key
If you used the muck template to create your rails application you will have a secrets.yml file. If not then you will need to create a secrets.yml file and then add the following to environment.rb right above Rails::Initializer.run do |config|
require 'ostruct'
require 'yaml'
::Secrets = OpenStruct.new(YAML.load_file(File.('../secrets.yml', __FILE__))[Rails.env])
Omit secrets.yml from your version control system and use it to keep sensitive data like email server credentials
email_user_name: 'TODO_admin@#{domain_name}' # Email server username
email_password = 'TODO_password' # Email server password
production:
<<: *DEFAULT
# Add production only secrets
staging:
<<: *DEFAULT
# Add staging only secrets
development:
<<: *DEFAULT
# Development specific
test:
<<: *DEFAULT
# Test specific
Usage
Create a model called profile.rb as show below. This mixes in the muck profile functionality but also permits further customization of the profile in your application.
class Profile < ActiveRecord::Base
include MuckProfiles::Models::MuckProfile
end
Modify your user model so that it has a profile:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.crypto_provider = Authlogic::CryptoProviders::BCrypt
end
include MuckUsers::Models::MuckUser
include MuckProfiles::Models::MuckUser
end
Your user model will now appear to have a ‘photo’ which is delegated to the profile model:
@user.photo # returns a photo object from paperclip
Configuration
Create an initializer to configure muck profiles:
MuckProfiles.configure do |config|
config.enable_sunspot = false # This enables or disables sunspot for profiles. Only use acts_as_solr or sunspot not both. Sunspot does not include multicore support.
config.enable_solr = true # This enables or disables acts as solr for profiles.
config.enable_guess_location = true # If true the profile system will attempt to determine the user's location via IP and populated with the location, lat and lon fields.
end
Acts as Solr
Muck Profiles works with solr to allow searching users.
If you enable acts_as_solr or sunspot you’ll also want to specify a default policy in your configuration. This policy is used to determine which fields are public and private. The default policy looks like this:
MuckProfiles.configure do |config|
config.enable_sunspot = false # This enables or disables sunspot for profiles. Only use acts_as_solr or sunspot not both. Sunspot does not include multicore support.
config.enable_solr = false # This enables or disables acts as solr for profiles. You will need to include muck-solr in your gemfile.
config.enable_geokit = false # Turn geokit functionality on/off. You will need to include geokit in your gemfile.
config.enable_guess_location = true # If true the profile system will attempt to determine the user's location via IP and populated with the location, lat and lon fields.
config.policy => { :public => [:login, :first_name, :last_name, :about],
:authenticated => [:location, :city, :state_id, :country_id, :language_id],
:friends => [:email],
:private => [] }
end
If you add attributes to the profile as show below then you will want to specify which fields fall into each privacy setting. Note that it is also possible to add new privacy levels simply by adding new values to the hash. For example:
MuckProfiles.configure do |config|
config.enable_sunspot = false # This enables or disables sunspot for profiles. Only use acts_as_solr or sunspot not both. Sunspot does not include multicore support.
config.enable_solr = true # This enables or disables acts as solr for profiles.
config.enable_guess_location = true # If true the profile system will attempt to determine the user's location via IP and populated with the location, lat and lon fields.
config.policy => { :public => [:login, :first_name, :last_name, :about],
:authenticated => [:location, :city, :state_id, :country_id, :language_id],
:friends => [:email],
:private => [] ,
:instructors => [:grades]}
end
For each top level key a method will be auto generated that returns the values from each attribute concatenated together. Assuming we have a profile with fields populated calling each method might return something like this:
@profile.public_fields # returns 'testguy test guy I am the test guy'
@profile.authenticated_fields # returns 'somewhere USA English'
@profile.friends_fields # returns '[email protected]'
@profile.private_fields # returns ' '
Solr will index these fields and then permit you to search based on each privacy level.
Profile Attributes
The profile comes preconfigured with a basic set of common profile options. It is easy to add new fields. Simply add the fields to the profile using a migration:
class AddMoreFieldsToProfiles < ActiveRecord::Migration
def self.up
add_column :profiles, :occupation, :string
add_column :profiles, :gender, :string
add_column :profiles, :birthday, :datetime
add_column :profiles, :company, :string
add_column :profiles, :zip, :string
add_column :profiles, :mobile_phone, :string
add_column :profiles, :home_phone, :string
add_column :profiles, :alumni_of, :string
add_column :profiles, :relationship_status, :string
end
def self.down
add_column :profiles, :occupation
add_column :profiles, :gender
add_column :profiles, :birthday
add_column :profiles, :company
add_column :profiles, :zip
add_column :profiles, :mobile_phone
add_column :profiles, :home_phone
add_column :profiles, :alumni_of
add_column :profiles, :relationship_status
end
end
Next create a new views/profiles/edit.html.erb file. The built in file is very basic and makes it easy to add additional fields. The ‘profile_form’ method will create form elements for the built in fields. Add extra fields after that.
<div id="edit_content" class="span-24 colborder column">
<%= output_errors(t('muck.profiles.problem_editing_profile'), {:class => 'help-box'}, @user) %>
<%= profile_form(@user) do |f| -%>
<%# can add form fields as desired here -%>
<% end -%>
</div>
Last create view/profiles/show.html.erb. There is a built in show page however it is assumed that most applications will implement a custom show page to hightlight the focus of the system.
<div class="span-24 colborder column">
<%= icon @user, :thumb %>
<p><%= @user.full_name %></p>
<p><%= link_to t('muck.profiles.edit_profile'), edit_user_profile_path(@user) if @profile.can_edit?(current_user) %></p>
<!-- Add more fields and customize the profile. -->
</div>
It’s important to sanitize user input. If you add fields to the profile then be sure to prevent cross site scripting. Override the ‘sanitize_attributes’ method in your model and add your new fields. Note that you can also override ‘sanitize_level’ to determine how sanitization occurs.
# Sanitize content before saving. This prevents XSS attacks and other malicious html.
def sanitize_attributes
if self.sanitize_level
self.about = Sanitize.clean(self.about, self.sanitize_level)
self.location = Sanitize.clean(self.location, self.sanitize_level)
# add your fields
end
end
# Override this method to control sanitization levels.
# Currently a user who is an admin will not have their content sanitized. A user
# in any role 'editor', 'manager', or 'contributor' will be given the 'RELAXED' settings
# while all other users will get 'BASIC'.
#
# Options are from sanitze:
# nil - no sanitize
# Sanitize::Config::RELAXED
# Sanitize::Config::BASIC
# Sanitize::Config::RESTRICTED
# for more details see: http://rgrove.github.com/sanitize/
def sanitize_level
return Sanitize::Config::BASIC if self.user.nil?
return nil if self.user.admin?
return Sanitize::Config::RELAXED if self.user.any_role?('editor', 'manager', 'contributor')
Sanitize::Config::BASIC
end
Copyright © 2009-2010 Tatemae, released under the MIT license