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.
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.