Не удается передать объект 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
не проверял, надеюсь что все будет хорошо