Search code examples
ruby-on-railsdelayed-jobrails-activejob

Can't pass CollectionProxy object to ActiveJob


I need to mark a collection of messages at the background (I am using delayed_job gem) since it takes some time on the foreground. So I've created an ActiveJob class MarkMessagesAsReadJob, and passed it user and messages variables in order to mark all of the messages read for user.

// passing the values in the controller
@messages     = @conversation.messages
MarkMessagesAsReadJob.perform_later(current_user, @messages) 

and in my ActiveJob class, I perform the task.

// MarkMessagesAsReadJob.rb
class MarkMessagesAsReadJob < ActiveJob::Base
  queue_as :default

  def perform(user, messages)
    messages.mark_as_read! :all, :for => user
  end
end

However, when I tried to perform the task, I got the error ActiveJob::SerializationError (Unsupported argument type: ActiveRecord::Associations::CollectionProxy):

I read that we can only pass supported types to the ActiveJob, and I think it can not serialize the CollectionProxy object. How can I workaround/fix this?

PS: I considered

@messages.map { |message| MarkMessagesAsReadJob.perform_later(current_user, message) } 

however I think marking them one by one is pretty expensive .


Solution

  • I think the easy way is pass message ids to the perform_later() method, for example:

    in controller:

    @messages = @conversation.messages
    message_ids = @messages.pluck(:id)
    MarkMessagesAsReadJob.perform_later(current_user, message_ids) 
    

    And use it in ActiveJob:

    def perform(user, message_ids)
      messages = Message.where(id: message_ids)
      messages.mark_as_read! :all, :for => user
    end