无法将 CollectionProxy 对象传递给 ActiveJob
Can't pass CollectionProxy object to ActiveJob
我需要在后台标记一组消息(我正在使用delayed_job gem),因为它在前台需要一些时间。所以我创建了一个 ActiveJob
class MarkMessagesAsReadJob
,并传递给它 user
和 messages
变量以标记所有 messages
已读user
.
// passing the values in the controller
@messages = @conversation.messages
MarkMessagesAsReadJob.perform_later(current_user, @messages)
并在我的 ActiveJob class 中执行任务。
// 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 对象。我怎么能workaround/fix这个?
PS: 我考虑过
@messages.map { |message| MarkMessagesAsReadJob.perform_later(current_user, message) }
但是我认为一个一个标记它们非常昂贵。
我认为简单的方法是将消息 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
因为作业会在稍后执行,我认为我们应该将 id 作为参数而不是集合作为参数传递
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
未测试,希望没问题
对于较大的数据集,传递 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
我需要在后台标记一组消息(我正在使用delayed_job gem),因为它在前台需要一些时间。所以我创建了一个 ActiveJob
class MarkMessagesAsReadJob
,并传递给它 user
和 messages
变量以标记所有 messages
已读user
.
// passing the values in the controller
@messages = @conversation.messages
MarkMessagesAsReadJob.perform_later(current_user, @messages)
并在我的 ActiveJob class 中执行任务。
// 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 对象。我怎么能workaround/fix这个?
PS: 我考虑过
@messages.map { |message| MarkMessagesAsReadJob.perform_later(current_user, message) }
但是我认为一个一个标记它们非常昂贵。
我认为简单的方法是将消息 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
因为作业会在稍后执行,我认为我们应该将 id 作为参数而不是集合作为参数传递
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
未测试,希望没问题
对于较大的数据集,传递 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