Не удается передать объект CollectionProxy в ActiveJob

Мне нужно пометить коллекцию сообщений на заднем плане (я использую гем delayed_job), поскольку на переднем плане это занимает некоторое время. Итак, я создал ActiveJob учебный класс MarkMessagesAsReadJobи передал его user а также messages переменные для того, чтобы отметить все messages читать для user,

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

и в моем классе ActiveJob я выполняю задачу.

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

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

Однако, когда я попытался выполнить задачу, я получил ошибку ActiveJob:: SerializationError (Неподдерживаемый тип аргумента: ActiveRecord:: Associations:: CollectionProxy):

Я прочитал, что мы можем передавать только поддерживаемые типы в ActiveJob, и я думаю, что он не может сериализовать объект CollectionProxy. Как я могу обойти / исправить это?

PS: я считал

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

однако я думаю, что пометить их по одному довольно дорого.

2 ответа

Решение

Я думаю, что самый простой способ - передать идентификаторы сообщений perform_later() метод, например:

в контроллере:

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

И использовать его в ActiveJob:

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

Для больших наборов данных передача message_ids нецелесообразна. Вместо этого передайте SQL для сообщений:

@messages = @conversation.messages
MarkMessagesAsReadJob.perform_later(current_user, @messages.to_sql) 

затем запросите их в работе:

class MarkMessagesAsReadJob < ActiveJob::Base
  queue_as :default
  def perform(user, messages_sql)
    messages = Message.find_by_sql(messages_sql) 
    messages.mark_as_read! :all, :for => user
  end
end

Поскольку задание будет выполнено позже, я думаю, что мы должны передать идентификаторы в качестве параметра вместо коллекции

ActiveJob требуется параметр сериализации, и SerializationError будет выдан, если тип параметра не поддерживается http://api.rubyonrails.org/classes/ActiveJob/SerializationError.html

например:

@message_ids = @conversation.messages.pluck(:id)
# use string if array is not supported
# @message_ids = @message_ids.join(", ")
MarkMessagesAsReadJob.perform_later(current_user, @message_ids) 

затем запросите эти сообщения снова и отметьте его

class MarkMessagesAsReadJob < ActiveJob::Base
  queue_as :default
  def perform(user, message_ids)
    # use string if array is not supported
    # message_ids = message_ids.split(",").map(&:to_i)
    messages = Message.where(id: message_ids) #change this to something else
    messages.mark_as_read! :all, :for => user
  end
end

не проверял, надеюсь что все будет хорошо

Другие вопросы по тегам