5

我需要在后台标记一组消息(我正在使用delayed_job gem),因为在前台需要一些时间。所以我创建了一个ActiveJobMarkMessagesAsReadJob,并传递了它usermessages变量,以标记所有的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 (Unsupported argument type: ActiveRecord::Associations::CollectionProxy):

我读到我们只能将支持的类型传递给 ActiveJob,我认为它不能序列化 CollectionProxy 对象。我该如何解决/解决这个问题?

PS:我考虑过

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

但是我认为一一标记它们非常昂贵。

4

3 回答 3

8

我认为最简单的方法是将消息 ID 传递给该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: message_ids)
  messages.mark_as_read! :all, :for => user
end
于 2015-08-22T09:21:29.803 回答
4

因为作业将在稍后执行,我认为我们应该将 ids 作为参数而不是集合传递

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

没测试,希望没问题

于 2015-08-22T09:33:20.140 回答
4

对于较大的数据集,传递 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
于 2020-01-12T21:56:58.283 回答