Reputation: 1395
I have been trying to brainstorm on how I can calculate a users response rate (% of responses to messages received) and time (how fast does user responds to messages). This information would show on a users profile. I can't think of a formula that would work for this and haven't seen any other posting regarding it.
For example User A response rate is 85% and their response time is 3 days. What would be the proper way to attack this?
Messages model:
attr_accessible :subject, :body, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
validates_presence_of :subject, :message => "Please enter message title"
has_many :notifications, as: :event
scope :unread, -> {where('read_at IS NULL')}
belongs_to :sender,
:class_name => 'User',
:foreign_key => 'sender_id'
belongs_to :recipient,
:class_name => 'User',
:foreign_key => 'recipient_id'
# Based on if a message has been read by it's recipient returns true or false.
def read?
self.read_at.nil? ? false : true
end
def self.received_by(user)
where(:recipient_id => user.id)
end
def self.not_recipient_deleted
where("recipient_deleted = ?", false)
end
def self.sent_by(user)
Message.where(:sender_id => user.id)
end
Controller:
before_filter :set_user
def index
@messages = Message.scoped
@message = Message.new
if params[:mailbox] == "sent"
@messages = @user.sent_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
elsif params[:mailbox] == "inbox"
@messages = @user.received_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
#elsif params[:mailbox] == "archived"
# @messages = @user.archived_messages
end
if params[:mailbox] == "unread"
@messages = @user.unread_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
end
if params[:mailbox] == "trash"
@messages = @user.deleted_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
end
end
def new
@message = Message.new
@message.conversation_id = params[:conversation_id]
end
def create
@message = Message.new(params[:message])
@message.sender_id = @user.id
if @message.save
flash[:notice] = "Message has been sent"
redirect_to user_messages_path(current_user, :mailbox=>:inbox)
else
render :action => :new
end
end
def show
@reply_message = Message.new
@message = Message.find(params[:id])
if @message.recipient == current_user
UserMessageWorker.perform_async(@message.id, current_user.id)
end
@message.readingmessage if @message.recipient == current_user
end
def reply
@reply_message = Message.new
@message = Message.new
@message.conversation_id = params[:conversation_id]
end
def destroy
@message = Message.find(params[:id])
@message.destroy
flash[:notice] = "Successfully deleted message."
redirect_to user_messages_path(@user, @messages)
end
def delete_multiple
if params[:delete]
params[:delete].each { |id|
@message = Message.find(id)
@message.mark_message_deleted(@message.id,@user.id) unless @message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to user_messages_path(@user, @messages)
end
def update
@message = Message.new
if params[:reply_to]
@reply_to = User.find_by_id(params[:reply_to])
unless @reply_to.nil?
@message.recipient_id = @reply_to.id
end
end
end
private
def set_user
@user = current_user
end
end
Log:
2014-02-05T17:08:16Z 33906 TID-zt6cxk WARN: {"retry"=>true, "queue"=>"default", "class"=>"UserMessageWorker", "args"=>[159, 2], "jid"=>"f502221628588feaa5efa7d3", "enqueued_at"=>1391619720.3566332, "error_message"=>"undefined method `messages' for #<User:0x00000101edb0a0>", "error_class"=>"NoMethodError", "failed_at"=>"2014-02-05T17:02:00Z", "retry_count"=>4, "retried_at"=>2014-02-05 17:08:16 UTC}
2014-02-05T17:08:16Z 33906 TID-zt6cxk WARN: undefined method `messages' for #<User:0x00000101edb0a0>
2014-02-05T17:08:16Z 33906 TID-zt6cxk WARN: /Users/.rvm/gems/ruby-2.0.0-p353/gems/activemodel-4.0.0.rc1/lib/active_model/attribute_methods.rb:436:in `method_missing'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/activerecord-4.0.0.rc1/lib/active_record/attribute_methods.rb:131:in `method_missing'
/Users/dating/app/workers/user_message_worker.rb:8:in `perform'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:49:in `block (3 levels) in process'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:122:in `call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:122:in `block in invoke'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/server/active_record.rb:6:in `call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/server/retry_jobs.rb:62:in `call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/server/logging.rb:11:in `block in call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/logging.rb:22:in `with_context'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/server/logging.rb:7:in `call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:127:in `call'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/middleware/chain.rb:127:in `invoke'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:48:in `block (2 levels) in process'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:105:in `stats'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:47:in `block in process'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:86:in `do_defer'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/sidekiq-2.17.2/lib/sidekiq/processor.rb:37:in `process'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `public_send'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `dispatch'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/calls.rb:122:in `dispatch'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/actor.rb:322:in `block in handle_message'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/actor.rb:416:in `block in task'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/tasks.rb:55:in `block in initialize'
/Users/.rvm/gems/ruby-2.0.0-p353/gems/celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb:13:in `block in create'
Upvotes: 3
Views: 1157
Reputation: 1534
I'm assuming you will want to store these values in the User table? I'll call those columns average_response_time
and response_rate
. You will also want to add a column to the User table that is a sum of all the Time between when a message is sent and when it is seen. I'll call it response_total
.
Then put it all in a background job... or not, but I would. I like Sidekiq, and there's a great railscast about it here.
In messages controller
def show
@message = Message.find(params[:id])
if @message.recipient == current_user
UserMessageWorker.perform_async(@message.id, current_user.id)
end
end
Then in app/workers/user_message_worker.rb
class UserMessageWorker
include Sidekiq::Worker
def perform(message_id, user_id)
message = Message.find(message_id)
user = User.find(user_id)
message.read_at = Time.now
old_msg_count = user.messages.count
if message.save
msg_response_time = message.read_at - message.created_at
response_rate = (user.messages.where("read_at IS NOT NULL").count)/(old_msg_count + 1)
response_time = ((user.average_response_time * old_msg_count)+msg_response_time)/(old_msg_count + 1)
user.update_attributes(:response_rate => response_rate, :average_response_time => average_response_time )
end
end
end
I'm pretty sure my math for the response_time
is correct, but you should double check it. Also, depending on how accurate you want it, you may want to store response_total
in minutes or seconds (or hours or days) so the number doesn't get huge.
Upvotes: 5