Add social networking to your site with the Has Many Friends plugin. With this tutorial your site users can search for other users by email address and send a friend request. If the request is accepted, a friendship is established and the social networking commences. If the searched for site user is not yet a member, an email invitation can be sent out.
This tutorial assumes that you already have a base project set up with a users table that has login and email columns. If you are starting from scratch I suggest you take a look at the Cortex Engine — a base rails setup that includes user authentication with authlogic, action-mailers and a few other features to get you up and running.
This tutorial uses a little bit of Ajax and requires that prototype is linked to in the head section of your layout. If you are using the Cortex Engine please see the JavaScript section of the readme.
Install the HasManyFriends plugin
script/plugin install git://github.com/swemoney/has_many_friends.git
Run the generator
script/generate hmf_friendship_model Friendship
This will set up your friendship model and create a migration file:
class CreateFriendships < ActiveRecord::Migration
def self.up
create_table :friendships, :force => true do |t|
t.column "user_id", :integer, :null => false
t.column "friend_id", :integer, :null => false
t.column "created_at", :datetime
t.column "accepted_at", :datetime
end
end
def self.down
drop_table :friendships
end
end
Rake the migration
rake db:migrate
Generate a controller
script/generate controller friendships
The invitation action uses action-mailer to send invitations to become a site member. We will write the mailer part later in the tutorial. Notice: the format.js in the respond_to block, we need this for our Ajax function (invitation.rjs).
def invitation
user = current_user
recipient = params[:email]
UserMailer.deliver_invite(user, recipient)
flash[:notice] = "Invitation Sent"
respond_to do |format|
format.html
format.js
end
end
The index action lets us search for friends and returns an Ajax response.
def index
@lookup = params[:search]
@result= User.find(:first, :conditions =>['email = ?', @lookup ])
@friends = current_user.friends
respond_to do |format|
format.html
format.js
end
end
The show action
def show
@friends = current_user.friends
@pending_by_me = current_user.pending_friends_by_me
@pending_for_me = current_user.pending_friends_for_me
end
The new action initiates the friendship by sending a request to the specified user.
def new
@user=current_user
@rf = User.find(params[:id])
@user.request_friendship_with @rf
flash[:notice] = "sent friendship request to #{@rf.login.capitalize} "
redirect_to :back
end
The accept action completes the frindship
def accept
@user=current_user
@accept = User.find(params[:id])
@user.accept_friendship_with @accept
redirect_to :back
end
The sever action deletes the friendship
def sever
@user = current_user
@id = params[:id]
@sever = User.find(@id)
@user.delete_friendship_with @sever
flash[:notice] = "friendship canceled"
redirect_to :back
end
Add routing to config/routes
map.resources :friendships
The show template handles 5 different actions. It displays a friends list, contains a search form that returns an Ajax response, displays a list of friendship requests (from other users) and displays a list of sent friendship requests.
<h3>Manage Friends</h3>
<b>My Friends</b><br>
<%@friends.each do |fr| %>
<%= fr.login.capitalize %>
<%= link_to "Delete", :controller => 'friendships', :action => 'sever', :id => fr.id %>
<%end%>
<% form_remote_tag :url => '/friendships/index' do %>
Find friends by email address
<%= text_field_tag :search, params[:search], :size => 20 %>
<%= submit_tag "Search" %>
<% end %>
<div id = 'ajax_space'></div> <!-- provides a space for the Ajax response-->
<% if @pending_for_me.size > 0 %><!-- only displays if user has friendship requests -->
<div>
<b>Frindship Requests:</b>
<ul>
<% @pending_for_me.each do |pfm|%>
<li>
<%= pfm.login.capitalize %>,
<%= pfm.email%>
<%= link_to ' ...Accept', :controller => 'friendships', :action => 'accept', :id => pfm.id %>
</li>
<%end%>
</ul>
</div>
<%end%>
<% if @pending_by_me.size > 0 %><!-- only displays if user has pending friendship requests -->
<div>
<b>You have sent a friendship request to:</b>
<ul>
<% @pending_by_me.each do |pbf|%>
<li><%= pbf.login.capitalize %>, <%= pbf.email%> </li>
<%end%>
</ul>
</div>
<%end%>
The index partial shows the search response
<% if @result.blank? %>
A user with email: <b><%= @lookup %></b> was not found.
<%= link_to_remote 'Email an invitation?', :url=> {:controller => 'friendships',
:action =>'invitation', :email => @lookup}, :method => 'post'%>
<%else%>
User found:
<%= @result.login.capitalize%>,
<%= @result.email %>
<% if @friends.include? @result %>
is already in your share list.
<%else%>
<%= link_to 'Send Share Request?', :controller => 'friendships', :action => 'new', :id => @result.id%>
<%end%>
<%end%>
page.reload page[:search].value = ""
page.insert_html :bottom, :ajax_space, :partial => 'index' flash.discard
The mailer settings are set up to use smtp with gmail.
class UserMailer < ActionMailer::Base
def invite(user, recipient)
@user=user
@subject = "Invitation"
@from = "my website"
@body[:url] = "http://192.168.1.3:3004" #set to your ip address or domain name
@recipients = recipient
@sent_on = Time.now
content_type 'text/html'
end
end
require "smtp_tls"
mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
mailer_options = YAML.load(mailer_config)
ActionMailer::Base.smtp_settings = mailer_options
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:authentication => :plain,
:enable_starttls_auto => true,
:user_name => "your gmail address",
:password => "your gmail password"
}
:address: smtp.gmail.com :port: 587 :user_name: your gmail address :authentication: plain
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body>
<h4>Welcome, </h4>
<p>
<%= @user.login.capitalize %> ( <%= @user.email %> ) has invited you to join this web site.
</p>
<p>
To sign up or for more information go to <%= @url %>.
</p>
<p>Thanks, <br>
The Web
</p>
</body>
</html>
Welcome, <%= @user.login.capitalize %> (<%= @user.email %>) has invited you to join this web site. To sign up or for more information go to <%= @url %>. Thanks, The Web
Fire up your server and test everything out.