From 7b3a2b07ee164f4928fcf7cdba1fe35227b077f5 Mon Sep 17 00:00:00 2001
From: Raphael Sofaer <raphael@joindiaspora.com>
Date: Wed, 9 Feb 2011 14:12:21 -0800
Subject: [PATCH] Removed n-query, created mentions table

---
 app/models/mention.rb                        | 10 ++++++
 app/models/post.rb                           |  3 +-
 app/models/status_message.rb                 | 19 +++++++++--
 db/migrate/20110209204702_create_mentions.rb | 15 +++++++++
 db/schema.rb                                 | 11 ++++++-
 spec/models/status_message_spec.rb           | 33 +++++++++++++++++---
 6 files changed, 83 insertions(+), 8 deletions(-)
 create mode 100644 app/models/mention.rb
 create mode 100644 db/migrate/20110209204702_create_mentions.rb

diff --git a/app/models/mention.rb b/app/models/mention.rb
new file mode 100644
index 0000000000..deb065b675
--- /dev/null
+++ b/app/models/mention.rb
@@ -0,0 +1,10 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+class Mention < ActiveRecord::Base
+  belongs_to :post
+  belongs_to :person
+  validates_presence_of :post
+  validates_presence_of :person
+end
diff --git a/app/models/post.rb b/app/models/post.rb
index df28343702..98671c505c 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -17,6 +17,7 @@ class Post < ActiveRecord::Base
   has_many :comments, :order => 'created_at ASC', :dependent => :destroy
   has_many :post_visibilities
   has_many :aspects, :through => :post_visibilities
+  has_many :mentions, :dependent => :delete_all
   belongs_to :person
 
   cattr_reader :per_page
@@ -81,7 +82,7 @@ class Post < ActiveRecord::Base
       else
         user.add_post_to_aspects(local_post)
         Rails.logger.info("event=receive payload_type=#{self.class} update=true status=complete sender=#{self.diaspora_handle} existing_post=#{local_post.id}")
-        return local_post 
+        return local_post
       end
     elsif !local_post
       self.save
diff --git a/app/models/status_message.rb b/app/models/status_message.rb
index 9ee3c0e8c5..dc500e0f97 100644
--- a/app/models/status_message.rb
+++ b/app/models/status_message.rb
@@ -43,17 +43,32 @@ class StatusMessage < Post
       person = people.detect{ |p|
         p.diaspora_handle == inner_captures.last
       }
-      person ? "<a href=\"/people/#{person.id}\">#{ERB::Util.h(person.name)}</a>" : inner_captures.first
+      person ? "<a href=\"/people/#{person.id}\" class=\"mention\">#{ERB::Util.h(person.name)}</a>" : ERB::Util.h(inner_captures.first)
     end
     form_message
   end
 
   def mentioned_people
+    if self.persisted?
+      create_mentions if self.mentions.empty?
+      self.mentions.includes(:person => :profile).map{ |mention| mention.person }
+    else
+      mentioned_people_from_string
+    end
+  end
+
+  def create_mentions
+    mentioned_people_from_string.each do |person|
+      self.mentions.create(:person => person)
+    end
+  end
+
+  def mentioned_people_from_string
     regex = /@\{([^;]+); ([^\}]+)\}/
     identifiers = self.raw_message.scan(regex).map do |match|
       match.last
     end
-    Person.where(:diaspora_handle => identifiers)
+    identifiers.empty? ? [] : Person.where(:diaspora_handle => identifiers)
   end
 
   def to_activity
diff --git a/db/migrate/20110209204702_create_mentions.rb b/db/migrate/20110209204702_create_mentions.rb
new file mode 100644
index 0000000000..d4bbbf39e8
--- /dev/null
+++ b/db/migrate/20110209204702_create_mentions.rb
@@ -0,0 +1,15 @@
+class CreateMentions < ActiveRecord::Migration
+  def self.up
+    create_table :mentions do |t|
+      t.integer :post_id, :null => false
+      t.integer :person_id, :null => false
+    end
+    add_index :mentions, :post_id
+    add_index :mentions, :person_id
+    add_index :mentions, [:person_id, :post_id], :unique => true
+  end
+
+  def self.down
+    drop_table :mentions
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c4fbefa114..3c0a97c169 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20110202015222) do
+ActiveRecord::Schema.define(:version => 20110209204702) do
 
   create_table "aspect_memberships", :force => true do |t|
     t.integer  "aspect_id",  :null => false
@@ -95,6 +95,15 @@ ActiveRecord::Schema.define(:version => 20110202015222) do
   add_index "invitations", ["recipient_id"], :name => "index_invitations_on_recipient_id"
   add_index "invitations", ["sender_id"], :name => "index_invitations_on_sender_id"
 
+  create_table "mentions", :force => true do |t|
+    t.integer "post_id",   :null => false
+    t.integer "person_id", :null => false
+  end
+
+  add_index "mentions", ["person_id", "post_id"], :name => "index_mentions_on_person_id_and_post_id", :unique => true
+  add_index "mentions", ["person_id"], :name => "index_mentions_on_person_id"
+  add_index "mentions", ["post_id"], :name => "index_mentions_on_post_id"
+
   create_table "mongo_aspect_memberships", :force => true do |t|
     t.string   "aspect_mongo_id"
     t.string   "contact_mongo_id"
diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb
index acf4551769..320b650863 100644
--- a/spec/models/status_message_spec.rb
+++ b/spec/models/status_message_spec.rb
@@ -73,8 +73,8 @@ STR
     describe '#formatted_message' do
       it 'adds the links in the formated message text' do
         @sm.formatted_message.should == <<-STR
-#{link_to(@people[0].name, person_path(@people[0]))} can mention people like Raphael #{link_to(@people[1].name, person_path(@people[1]))}
-can mention people like Raphaellike Raphael #{link_to(@people[2].name, person_path(@people[2]))} can mention people like Raph
+#{link_to(@people[0].name, person_path(@people[0]), :class => 'mention')} can mention people like Raphael #{link_to(@people[1].name, person_path(@people[1]), :class => 'mention')}
+can mention people like Raphaellike Raphael #{link_to(@people[2].name, person_path(@people[2]), :class => 'mention')} can mention people like Raph
 STR
       end
       it 'leaves the name of people that cannot be found' do
@@ -102,8 +102,33 @@ STR
       end
     end
 
-    it 'extracts the mentioned people from the message' do
-      @sm.mentioned_people.to_set.should == @people.to_set
+    describe '#mentioned_people_from_string' do
+      it 'extracts the mentioned people from the message' do
+        @sm.mentioned_people_from_string.to_set.should == @people.to_set
+      end
+    end
+    describe '#create_mentions' do
+      it 'creates a mention for everyone mentioned in the message' do
+        @sm.should_receive(:mentioned_people_from_string).and_return(@people)
+        @sm.mentions.delete_all
+        @sm.create_mentions
+        @sm.mentions(true).map{|m| m.person}.to_set.should == @people.to_set
+      end
+    end
+    describe '#mentioned_people' do
+      it 'calls create_mentions if there are no mentions in the db' do
+        @sm.mentions.delete_all
+        @sm.should_receive(:create_mentions)
+        @sm.mentioned_people
+      end
+      it 'returns the mentioned people' do
+        @sm.mentions.delete_all
+        @sm.mentioned_people.to_set.should == @people.to_set
+      end
+      it 'does not call create_mentions if there are mentions in the db' do
+        @sm.should_not_receive(:create_mentions)
+        @sm.mentioned_people
+      end
     end
   end
   describe "XML" do
-- 
GitLab