diff --git a/app/controllers/aspect_memberships_controller.rb b/app/controllers/aspect_memberships_controller.rb
index d9a55d761ea3c5bcbeafd154a999f562f82913af..189c1fb5b4d201000b9ddf7bee09e3797b624a9b 100644
--- a/app/controllers/aspect_memberships_controller.rb
+++ b/app/controllers/aspect_memberships_controller.rb
@@ -46,12 +46,11 @@ class AspectMembershipsController < ApplicationController
     @aspect = current_user.aspects.where(:id => params[:aspect_id]).first
 
     if @contact = current_user.share_with(@person, @aspect)
-      flash.now[:notice] =  I18n.t 'aspects.add_to_aspect.success'
+      flash.now[:notice] =  I18n.t('aspects.add_to_aspect.success')
       respond_with AspectMembership.where(:contact_id => @contact.id, :aspect_id => @aspect.id).first
     else
-      flash[:error] = I18n.t 'contacts.create.failure'
-      #TODO(dan) take this out once the .js template is removed
-      render :nothing => true
+      flash.now[:error] = I18n.t('contacts.create.failure')
+      render :nothing => true, :status => 409
     end
   end
 
diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb
index f842f59ece0171abd7282584a2972b5a36d7e9dd..623618ebba46bc5fb98126158e2d806fecd11fc1 100644
--- a/app/controllers/people_controller.rb
+++ b/app/controllers/people_controller.rb
@@ -95,6 +95,7 @@ class PeopleController < ApplicationController
 
     unless params[:format] == "json" # hovercard
       if current_user
+        @block = current_user.blocks.where(:person_id => @person.id).first
         @contact = current_user.contact_for(@person)
         @aspects_with_person = []
         if @contact && !params[:only_posts]
diff --git a/app/models/contact.rb b/app/models/contact.rb
index b1e961207229350bd9a397f148c3636bdb75e297..1d19283b12e3952c8c54fb6d8a9c70e6e410c749 100644
--- a/app/models/contact.rb
+++ b/app/models/contact.rb
@@ -15,7 +15,8 @@ class Contact < ActiveRecord::Base
   has_many :share_visibilities, :source => :shareable, :source_type => 'Post'
   has_many :posts, :through => :share_visibilities, :source => :shareable, :source_type => 'Post'
 
-  validate :not_contact_for_self
+  validate :not_contact_for_self,
+           :not_blocked_user
 
   validates_uniqueness_of :person_id, :scope => :user_id
 
@@ -98,5 +99,14 @@ class Contact < ActiveRecord::Base
       errors[:base] << 'Cannot create self-contact'
     end
   end
+
+  def not_blocked_user
+    if user.blocks.where(:person_id => person_id).exists?
+      errors[:base] << 'Cannot connect to an ignored user'
+      false
+    else
+      true
+    end
+  end
 end
 
diff --git a/app/views/people/_sub_header.html.haml b/app/views/people/_sub_header.html.haml
index 334c60fe4ed107c4b4349336b0199b9f39f83a95..e11abc0b211489e97b981fb46b1a8ecab2a3e35c 100644
--- a/app/views/people/_sub_header.html.haml
+++ b/app/views/people/_sub_header.html.haml
@@ -1,7 +1,13 @@
 #author_info
   .right
     - if user_signed_in? && current_user.person != person
-      = aspect_membership_dropdown(contact, person, 'right')
+      - if @block.present?
+        = link_to t('users.privacy_settings.stop_ignoring'), block_path(@block),
+          :method => :delete,
+          :class => "button"
+
+      - else
+        = aspect_membership_dropdown(contact, person, 'right')
     - elsif user_signed_in? && current_user.person == person
       = link_to t('people.profile_sidebar.edit_my_profile'), edit_profile_path, :class => 'button creation'
 
diff --git a/app/views/people/show.html.haml b/app/views/people/show.html.haml
index 1851527503df384df38c976eeb2647103a94cd52..314b6282fc460c78e80fe49e6644df36dfce3d21 100644
--- a/app/views/people/show.html.haml
+++ b/app/views/people/show.html.haml
@@ -39,5 +39,8 @@
     - else
       #main_stream
         %div{:style=>"text-align:center;", :class => "dull"}
-          = t('.has_not_shared_with_you_yet', :name => @person.first_name)
+          - if @block.present?
+            = t('.ignoring', :name => @person.first_name)
+          - else
+            = t('.has_not_shared_with_you_yet', :name => @person.first_name)
 
diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml
index 594d24a6a5a27a31e4994e373ead09a748ae2390..d1f4d555cf98af34712fc4d3bb5ad158b050f126 100644
--- a/config/locales/diaspora/en.yml
+++ b/config/locales/diaspora/en.yml
@@ -544,6 +544,7 @@ en:
       start_sharing: "start sharing"
       message: "Message"
       mention: "Mention"
+      ignoring: "You are ignoring all posts from %{name}."
     sub_header:
       you_have_no_tags: "you have no tags!"
       add_some: "add some"
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index 3e2e918772f84274383e1b0594400e14bfd8b8b7..3497eba47c73e6688cd60b6d38537249bed1a3f4 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -40,6 +40,7 @@ en:
         all_aspects: "All aspects"
         stopped_sharing_with: "You have stopped sharing with {{name}}."
         started_sharing_with: "You have started sharing with {{name}}!"
+        error: "Couldn't start sharing with {{name}}.  Are you ignoring them?"
         toggle:
           zero: "Select aspects"
           one: "In {{count}} aspect"
diff --git a/lib/diaspora/user/connecting.rb b/lib/diaspora/user/connecting.rb
index be2c150a60b3b8162a7080b596fade01a7e65044..47ef5f07a75d492ac5c4bb95e95d1f7cf51ef050 100644
--- a/lib/diaspora/user/connecting.rb
+++ b/lib/diaspora/user/connecting.rb
@@ -11,6 +11,8 @@ module Diaspora
       # @return [Contact] The newly made contact for the passed in person.
       def share_with(person, aspect)
         contact = self.contacts.find_or_initialize_by_person_id(person.id)
+        return false unless contact.valid?
+
         unless contact.receiving?
           contact.dispatch_request
           contact.receiving = true
diff --git a/public/javascripts/contact-edit.js b/public/javascripts/contact-edit.js
index 4e55200df2f4a2dd57f25d0d31e4f69633181135..0e00c1c08cc1a73b4c7261d451f4d92a37209226 100644
--- a/public/javascripts/contact-edit.js
+++ b/public/javascripts/contact-edit.js
@@ -6,7 +6,6 @@ var ContactEdit = {
   init: function(){
     $.extend(ContactEdit, AspectsDropdown);
     $('.dropdown.aspect_membership .dropdown_list > li, .dropdown.inviter .dropdown_list > li').live('click', function(evt){
-
       ContactEdit.processClick($(this), evt);
     });
    },
@@ -64,7 +63,10 @@ var ContactEdit = {
   },
 
   toggleAspectMembership: function(li, evt) {
-    var button = li.find('.button');
+    var button = li.find('.button'),
+        dropdown = li.closest('.dropdown'),
+        dropdownList = li.parent('.dropdown_list');
+
     if(button.hasClass('disabled') || li.hasClass('newItem')){ return; }
 
     var selected = li.hasClass("selected"),
@@ -75,12 +77,19 @@ var ContactEdit = {
       "person_id": li.parent().data("person_id"),
       "_method": (selected) ? "DELETE" : "POST"
     }, function(aspectMembership) {
-      li.removeClass("loading");
       ContactEdit.toggleCheckbox(li);
       ContactEdit.updateNumber(li.closest(".dropdown_list"), li.parent().data("person_id"), aspectMembership.aspect_ids.length, 'in_aspects');
 
       Diaspora.page.publish("aspectDropdown/updated", [li.parent().data("person_id"), li.parents(".dropdown").parent(".right").html()]);
-    });
+    })
+      .error(function() {
+        var message = Diaspora.I18n.t("aspect_dropdown.error", {name: dropdownList.data('person-short-name')});
+        Diaspora.page.flashMessages.render({success: false, notice: message});
+        dropdown.removeClass('active');
+      })
+      .complete(function() {
+        li.removeClass("loading");
+      });
   }
 };
 
diff --git a/spec/models/contact_spec.rb b/spec/models/contact_spec.rb
index 26cce4b5351dbb9cd9eb680788f81b6e926c8ede..1a3c507aa20007106b8e6c5adce5eb7f7a0ba21f 100644
--- a/spec/models/contact_spec.rb
+++ b/spec/models/contact_spec.rb
@@ -199,4 +199,27 @@ describe Contact do
       @contact.destroy
     end
   end
+
+  describe "#not_blocked_user" do
+    before do
+      @contact = alice.contact_for(bob.person)
+    end
+
+    it "is called on validate" do
+      @contact.should_receive(:not_blocked_user)
+      @contact.valid?
+    end
+
+    it "adds to errors if potential contact is blocked by user" do
+      person = eve.person
+      block = alice.blocks.create(:person => person)
+      bad_contact = alice.contacts.create(:person => person)
+
+      bad_contact.send(:not_blocked_user).should be_false
+    end
+
+    it "does not add to errors" do
+      @contact.send(:not_blocked_user).should be_true
+    end
+  end
 end