DEV: raise an exception when trying to create a post within a transaction (#11287)

DEV: raise an exception when trying to create a post within a transaction (#11287)

Hopefully this will prevent fellow developers from spending a morning trying to figure out why the jobs that are run after a post is created are not finding the post in the database.

That’s because if you’re inside a transaction when creating a post, the jobs will likely run before the transaction is being commited to the database.

There was a “warning” in the comments of the PostCreator class but raising an exception should hopefully help catch those issue much faster :fingers_crossed:.

This is hard to test since all the tests are run in a transaction…

diff --git a/lib/post_creator.rb b/lib/post_creator.rb
index eab06f3..ab3ad24 100644
--- a/lib/post_creator.rb
+++ b/lib/post_creator.rb
@@ -59,21 +59,20 @@ class PostCreator
     # TODO: we should reload user in case it is tainted, should take in a user_id as opposed to user
     # If we don't do this we introduce a rather risky dependency
     @user = user
+    @spam = false
     @opts = opts || {}
-    opts[:title] = pg_clean_up(opts[:title]) if opts[:title] && opts[:title].include?("\u0000")
-    opts[:raw] = pg_clean_up(opts[:raw]) if opts[:raw] && opts[:raw].include?("\u0000")
-    opts.delete(:reply_to_post_number) unless opts[:topic_id]
+
+    opts[:title] = pg_clean_up(opts[:title]) if opts[:title]&.include?("\u0000")
+    opts[:raw] = pg_clean_up(opts[:raw]) if opts[:raw]&.include?("\u0000")
     opts[:visible] = false if opts[:visible].nil? && opts[:hidden_reason_id].present?
-    @guardian = opts[:guardian] if opts[:guardian]
 
-    @spam = false
+    opts.delete(:reply_to_post_number) unless opts[:topic_id]
   end
 
   def pg_clean_up(str)
     str.gsub("\u0000", "")
   end
 
-  # True if the post was considered spam
   def spam?
     @spam
   end
@@ -83,7 +82,7 @@ class PostCreator
   end
 
   def guardian
-    @guardian ||= Guardian.new(@user)
+    @guardian ||= @opts[:guardian] || Guardian.new(@user)
   end
 
   def valid?
@@ -200,6 +199,10 @@ class PostCreator
   end
 
   def create
+    if !Rails.env.test? && ActiveRecord::Base.connection.open_transactions > 0 && !@opts[:skip_jobs]
+      raise "You must use 'skip_jobs = true' when creating a post inside a transaction, otherwise jobs won't run properly."
+    end
+
     if valid?
       transaction do
         build_post_stats

GitHub sha: 7af061fa

This commit appears in #11287 which was approved by davidtaylorhq. It was merged by ZogStriP.