diff --git a/app/models/post_action.rb b/app/models/post_action.rb index aedc65c35e8..8608e72647b 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -131,20 +131,36 @@ class PostAction < ActiveRecord::Base post.topic.posts_count != 1 end - post_action = create( post_id: post.id, - user_id: user.id, - post_action_type_id: post_action_type_id, - message: opts[:message], - staff_took_action: opts[:take_action] || false, - related_post_id: related_post_id, - targets_topic: !!targets_topic ) + where_attrs = { + post_id: post.id, + user_id: user.id, + post_action_type_id: post_action_type_id + } - if post_action && post_action.is_like? - BadgeGranter.update_badges(action: :post_like, post_id: post.id) + action_attributes = { + message: opts[:message], + staff_took_action: opts[:take_action] || false, + related_post_id: related_post_id, + targets_topic: !!targets_topic + } + + # First try to revive a trashed record + row_count = PostAction.where(where_attrs) + .with_deleted + .where("deleted_at IS NOT NULL") + .update_all(action_attributes.merge(deleted_at: nil)) + + if row_count == 0 + post_action = create(where_attrs.merge(action_attributes)) + if post_action && post_action.is_like? + BadgeGranter.update_badges(action: :post_like, post_id: post.id) + end + else + post_action = PostAction.where(where_attrs).first + post_action.update_counters end post_action - rescue ActiveRecord::RecordNotUnique # can happen despite being .create # since already bookmarked diff --git a/spec/models/post_action_spec.rb b/spec/models/post_action_spec.rb index e241917151e..587755e05b1 100644 --- a/spec/models/post_action_spec.rb +++ b/spec/models/post_action_spec.rb @@ -175,6 +175,19 @@ describe PostAction do end end + describe "undo/redo repeatedly" do + it "doesn't create a second action for the same user/type" do + PostAction.act(codinghorror, post, PostActionType.types[:like]) + PostAction.remove_act(codinghorror, post, PostActionType.types[:like]) + PostAction.act(codinghorror, post, PostActionType.types[:like]) + PostAction.where(post: post).with_deleted.count.should == 1 + PostAction.remove_act(codinghorror, post, PostActionType.types[:like]) + + # Check that we don't lose consistency into negatives + post.reload.like_count.should == 0 + end + end + describe 'when a user votes for something' do it 'should increase the vote counts when a user votes' do lambda {