Enterprise-scale social media platform serving 1M+ users with real-time messaging, intelligent content feeds, advanced recommendation algorithms, and robust moderation systems. Built with Ruby on Rails, PostgreSQL, and Redis for high-performance social networking.
Scalable Ruby on Rails architecture optimized for social interactions
High-performance Rails 7 application with advanced caching, database optimization, and scalable architecture serving millions of social interactions daily.
Action Cable WebSocket connections enabling real-time messaging, live notifications, instant reactions, and collaborative social experiences.
ML-powered content algorithm with personalized recommendations, trending topics, engagement optimization, and spam detection for enhanced user experience.
Elasticsearch-powered search with full-text indexing, real-time suggestions, filtered queries, and intelligent content discovery across the platform.
Automated content moderation with AI-powered detection, community reporting, admin tools, and comprehensive safety measures for user protection.
Comprehensive analytics dashboard with engagement metrics, user insights, content performance, and data-driven social networking optimization.
Advanced Rails patterns and social networking architecture
class FeedsController < ApplicationController
before_action :authenticate_user!
before_action :set_user_preferences
# Optimized social feed with intelligent caching
def show
@feed_posts = Rails.cache.fetch(feed_cache_key, expires_in: 5.minutes) do
generate_personalized_feed
end
# Track feed impression for analytics
FeedImpressionJob.perform_later(current_user.id, @feed_posts.map(&:id))
respond_to do |format|
format.html
format.json { render json: serialize_feed_posts(@feed_posts) }
format.turbo_stream { render :show }
end
end
private
def generate_personalized_feed
# Multi-source feed generation with scoring algorithm
friend_posts = Post.joins(user: :friendships)
.where(friendships: { friend_id: current_user.id, status: 'accepted' })
.includes(:user, :attachments, :reactions)
.recent
followed_posts = Post.joins(user: :follows)
.where(follows: { follower_id: current_user.id })
.includes(:user, :attachments, :reactions)
.recent
# Combine and score posts using machine learning
all_posts = (friend_posts + followed_posts).uniq
scored_posts = FeedScoringService.new(current_user, all_posts).calculate_scores
# Apply user preferences and filters
filtered_posts = apply_content_filters(scored_posts)
# Paginate results
Kaminari.paginate_array(filtered_posts)
.page(params[:page])
.per(20)
end
def apply_content_filters(posts)
posts = posts.reject { |post| blocked_content?(post) }
posts = posts.select { |post| matches_interests?(post) } if @user_preferences.interest_filtering?
posts = posts.reject { |post| seen_recently?(post) }
posts.sort_by { |post| -post.calculated_score }
end
def feed_cache_key
# Intelligent cache key with user context
"user_feed:#{current_user.id}:#{current_user.updated_at.to_i}:#{Time.current.to_i / 5.minutes}"
end
end
# Advanced feed scoring service with ML integration
class FeedScoringService
attr_reader :user, :posts
def initialize(user, posts)
@user = user
@posts = posts
end
def calculate_scores
posts.map do |post|
post.calculated_score = calculate_post_score(post)
post
end
end
private
def calculate_post_score(post)
base_score = 1.0
# Recency score (fresher content scores higher)
recency_score = calculate_recency_score(post.created_at)
# Engagement score (likes, comments, shares)
engagement_score = calculate_engagement_score(post)
# User relationship score (closer friends score higher)
relationship_score = calculate_relationship_score(post.user)
# Content relevance score (based on user interests)
relevance_score = calculate_relevance_score(post)
# Diversity penalty (avoid showing too much from same user)
diversity_penalty = calculate_diversity_penalty(post.user)
# ML model prediction
ml_score = get_ml_prediction(post)
# Weighted final score
final_score = (
base_score * 0.1 +
recency_score * 0.2 +
engagement_score * 0.25 +
relationship_score * 0.2 +
relevance_score * 0.15 +
ml_score * 0.1
) * diversity_penalty
final_score.round(4)
end
def calculate_engagement_score(post)
likes_weight = 1.0
comments_weight = 2.0
shares_weight = 3.0
total_engagement = (
post.reactions.likes.count * likes_weight +
post.comments.count * comments_weight +
post.shares.count * shares_weight
)
# Normalize based on post age
hours_old = (Time.current - post.created_at) / 1.hour
normalized_engagement = total_engagement / (1 + hours_old * 0.1)
# Apply logarithmic scaling to prevent viral posts from dominating
Math.log(1 + normalized_engagement)
end
def get_ml_prediction(post)
# Integration with ML model for engagement prediction
features = extract_post_features(post)
MLPredictionService.predict_engagement(user.id, features)
rescue => e
Rails.logger.error "ML prediction failed: #{e.message}"
0.5 # fallback score
end
end
# Real-time messaging with Action Cable
class MessagesController < ApplicationController
before_action :authenticate_user!
def create
@conversation = current_user.conversations.find(params[:conversation_id])
@message = @conversation.messages.build(message_params)
@message.sender = current_user
if @message.save
# Broadcast to conversation channel
ConversationChannel.broadcast_to(
@conversation,
{
type: 'new_message',
message: MessageSerializer.new(@message).as_json,
sender: UserSerializer.new(current_user, scope: :basic).as_json
}
)
# Send push notifications to offline users
notify_conversation_participants
# Update conversation timestamp
@conversation.touch(:last_activity_at)
render json: { status: 'success', message: @message }
else
render json: { status: 'error', errors: @message.errors }
end
end
private
def notify_conversation_participants
offline_participants = @conversation.participants
.where.not(id: current_user.id)
.offline
offline_participants.each do |participant|
PushNotificationJob.perform_later(
participant.id,
{
title: "#{current_user.display_name} sent you a message",
body: @message.body.truncate(100),
action_url: conversation_path(@conversation)
}
)
end
end
def message_params
params.require(:message).permit(:body, :message_type, attachments: [])
end
end
# app/channels/social_activity_channel.rb
class SocialActivityChannel < ApplicationCable::Channel
def subscribed
stream_from "social_activity:#{current_user.id}"
stream_from "global_activity" if current_user.admin?
# Track user online status
current_user.update(last_seen_at: Time.current, online: true)
# Broadcast user online status to friends
broadcast_online_status
end
def unsubscribed
current_user.update(online: false)
broadcast_offline_status
end
def react_to_post(data)
post = Post.find(data['post_id'])
reaction_type = data['reaction_type']
# Toggle reaction
existing_reaction = current_user.reactions.find_by(post: post)
if existing_reaction
if existing_reaction.reaction_type == reaction_type
existing_reaction.destroy
action = 'removed'
else
existing_reaction.update(reaction_type: reaction_type)
action = 'changed'
end
else
current_user.reactions.create(post: post, reaction_type: reaction_type)
action = 'added'
end
# Real-time broadcast to all viewers of this post
PostChannel.broadcast_to(
post,
{
type: 'reaction_update',
action: action,
reaction_type: reaction_type,
user: UserSerializer.new(current_user, scope: :basic).as_json,
total_reactions: post.reactions.group(:reaction_type).count
}
)
# Send notification to post author (if not self-reaction)
unless post.user == current_user
NotificationJob.perform_later(
post.user.id,
{
type: 'post_reaction',
actor: current_user,
post: post,
reaction_type: reaction_type
}
)
end
end
def start_typing(data)
conversation_id = data['conversation_id']
# Broadcast typing indicator to conversation participants
ConversationChannel.broadcast_to(
Conversation.find(conversation_id),
{
type: 'typing_start',
user_id: current_user.id,
user_name: current_user.display_name
}
)
end
def stop_typing(data)
conversation_id = data['conversation_id']
ConversationChannel.broadcast_to(
Conversation.find(conversation_id),
{
type: 'typing_stop',
user_id: current_user.id
}
)
end
private
def broadcast_online_status
# Notify friends about online status
current_user.friends.online.each do |friend|
ActionCable.server.broadcast(
"social_activity:#{friend.id}",
{
type: 'friend_online',
user: UserSerializer.new(current_user, scope: :basic).as_json
}
)
end
end
def broadcast_offline_status
current_user.friends.online.each do |friend|
ActionCable.server.broadcast(
"social_activity:#{friend.id}",
{
type: 'friend_offline',
user_id: current_user.id
}
)
end
end
end
# Background job for feed generation optimization
class OptimizeFeedJob < ApplicationJob
queue_as :default
def perform(user_id)
user = User.find(user_id)
# Pre-generate and cache personalized feed
feed_posts = FeedGenerationService.new(user).generate_optimized_feed
# Cache the pre-generated feed
Rails.cache.write(
"optimized_feed:#{user.id}",
feed_posts,
expires_in: 30.minutes
)
# Update user engagement metrics
UserEngagementMetrics.update_feed_metrics(user, feed_posts)
# Schedule next optimization
OptimizeFeedJob.set(wait: 1.hour).perform_later(user_id)
end
end
# Advanced content moderation service
class ContentModerationService
include HTTParty
attr_reader :content, :content_type
def initialize(content, content_type = :text)
@content = content
@content_type = content_type
end
def moderate
results = {}
# Run multiple moderation checks
results[:toxicity] = check_toxicity
results[:spam] = check_spam
results[:inappropriate_content] = check_inappropriate_content
results[:hate_speech] = check_hate_speech
# Combine results and determine action
overall_score = calculate_overall_risk_score(results)
{
approved: overall_score < 0.3,
flagged: overall_score >= 0.3 && overall_score < 0.7,
blocked: overall_score >= 0.7,
confidence: overall_score,
details: results
}
end
private
def check_toxicity
# Integration with external toxicity detection API
response = self.class.post(
'https://api.perspectiveapi.com/v1alpha1/comments:analyze',
{
headers: { 'Content-Type' => 'application/json' },
body: {
requestedAttributes: { TOXICITY: {} },
comment: { text: content }
}.to_json
}
)
response.dig('attributeScores', 'TOXICITY', 'summaryScore', 'value') || 0
rescue => e
Rails.logger.error "Toxicity check failed: #{e.message}"
0
end
def check_spam
# Custom spam detection logic
spam_indicators = [
excessive_caps?,
repeated_patterns?,
suspicious_links?,
promotional_content?
]
spam_indicators.count(true).to_f / spam_indicators.length
end
def calculate_overall_risk_score(results)
weights = {
toxicity: 0.3,
spam: 0.2,
inappropriate_content: 0.3,
hate_speech: 0.2
}
weighted_score = results.sum { |key, value| weights[key] * value }
[weighted_score, 1.0].min
end
end
Building meaningful connections through technology
Interested in creating scalable social networking applications? Let's discuss how these Ruby on Rails patterns can power your next social platform innovation.
Platform Performance
Real-world metrics demonstrating social platform scalability