ruby-on-railsrails-activerecordcarrierwave

Carrierwave returns path of tmp file instead of actual in a callback


In an application I wanted to send public file URL to a service in an after_create callback. So, the code (simplified) looked like this:

class UserProfile < ApplicationRecord
  mount_uploader :video, VideoUploader
  after_create :send_url_to_service

  private

  # Just logs the URL
  def send_url_to_service
    Rails.logger.info video.url
  end
end

To my frustration, after the upload, the send_url_to_service callback always logged the cached file path - something like 'uploads/tmp/1473900000-123-0001-0123/file.mp4' instead of 'uploads/user_profiles/video/1/file.mp4'. I tried to write a method to form the URL from the actual file path, but it did not work because the file wasn't there yet.

So, the question is, how do you obtain a final file URL in a situation like this?

P. S. Please note, this is a self-answered question, I just wanted to share my experience.


Solution

  • The solution for me was to use the after_commit ..., on: :create callback instead of after_create:

    class UserProfile < ApplicationRecord
      mount_uploader :video, VideoUploader
      after_commit :send_url_to_service, on: :create
    
      private
    
      # Just logs the URL
      def send_url_to_service
        Rails.logger.info video.url
      end
    end
    

    The answer is pretty obvious, though I wasted a long time wandering around it. Explanation is simple: after_commit callback fires only after all information is successfully persisted. In my case the file was not yet persisted to storage directory (on after_create stage) - that is why I got the temporary file url instead of the actual one. Hope this helps somebody and saves their time.