I wish to perform some expensive operation when my model changes, so I do it asynchronously in a delayed job. Inside this job, I need to be able to tell what exactly the changes were, so I'm passing my changed model as a parameter to the delayed job.
Now, it seems that delayed-job fetches a new (pristine) version of the model from the database when the job starts running, which does not have the tracked changes that I need.
class MyModel < ActiveRecord::Base
after_save :perform_async_job
def perform_async_job
# Here, "self.changes" contains the changes
Delayed::Job.enqeue(AsyncJobPerformer.new(self), ...)
end
end
class AsyncJobPerformer
def initialize(model)
@model = model
end
def perform
# Here, "@model.changes" is empty
end
end
I can, of course, pass just the changes
hash, and not the model itself, but it would make the delayed job code much more complex, as it needs to use the model instance anyway (so I'll need to fetch it and use both the model and the changes as separate objects).
Is there some way to pass the model to the delayed job while preserving the tracked changes?
Never send model objects to workers, just send id's. You will need to pass the changes hash. The worker won't be able to preserve the changes created by the object instance. So yes, you'll need to pass the changes to your worker.
class MyModel < ActiveRecord::Base
after_save :perform_async_job
def perform_async_job
# Here, "self.changes" contains the changes
Delayed::Job.enqeue(AsyncJobPerformer.new(self.class.name, self.id, self.changes), ...)
end
end
class AsyncJobPerformer
def initialize(model_name, model_id, params)
changes = params
@model = model_name.constantize.find(model_id)
#handle changes here with @model.update(changes) or a seperate method if need.
end
def perform
# Here, "@model.changes" is empty
end
end