Rails 4 - Resque 背景作业中的印象派

Rails 4 - Impressionist Inside of a Resque Background Job

我正在使用 Rails 4 w/ 印象派和 resque gem。

我正在使用印象派在我的文章显示页面上记录唯一会话点击。由于性能问题并且不需要向用户显示命中(仅供管理员使用),我想将日志记录移到后台。

通常我会使用 impressionist(@article, unique: [:session_hash]) 记录印象,但要通过 resque 将其移到背景中,我现在正在做这样的事情...

articles_controller:

def show
  .
  .
  .
  Resque.enqueue(ImpressionLogger, @article.id)
end

app/workers/impression_logger.rb:

class ImpressionLogger 

  @queue = :impression_queue

  def self.perform(article_id)
    article = Article.find(article_id)
    impressionist(article, unique: [:session_hash])
  end

end

当我这样设置时,当 resque 尝试处理作业时,它返回 undefined method "impressionist" for ImpressionLogger:Class。你们认为解决这个问题的最佳方法是什么?我不确定如何在我的 resque worker 中包含印象派方法。

印象派是否正确安装了捆绑器?如果是这样,Rails 应该将其加载到您的环境中。我会检查您是否可以在 Rails 代码的其他地方访问 impressionist 功能(即不通过 Resque)作为调试它的第一步。

你是如何启动你的 resque worker 的?如果您需要加载 Rails 环境,请尝试 rake environment resque:work.

https://github.com/resque/resque/wiki/FAQ#how-do-i-ensure-my-rails-classesenvironment-is-loaded

问题

你的问题源于这样一个事实,即印象派在控制器级别工作,因为在任何 ActionController 实例的引擎初始化程序中包含一个带有 impressionist 方法的模块:

https://github.com/charlotte-ruby/impressionist/blob/master/lib/impressionist/engine.rb#L11

您正在尝试从 Resque 作业中调用的常规 class 调用印象派方法,因此不会定义该方法。

解决方案

这有点恶心,但如果你真的想使用印象派,我们可以深入研究这个......看看发现的印象派方法的实际实现 here,我们看到以下内容:

def impressionist(obj,message=nil,opts={})
  if should_count_impression?(opts)
    if obj.respond_to?("impressionable?")
      if unique_instance?(obj, opts[:unique])
        obj.impressions.create(associative_create_statement({:message => message}))
      end
    else
      # we could create an impression anyway. for classes, too. why not?
      raise "#{obj.class.to_s} is not impressionable!"
    end
  end
end

假设您要手动调用这样的东西(正如您希望从 resque 作业中调用的那样),关键是以下三行:

if unique_instance?(obj, opts[:unique])
  obj.impressions.create(associative_create_statement({:message => message}))
end

if 包装器似乎只有在您想要实现 this functionality. Which it looks like you do. The call to associative_create_statement seems to be pulling parameters based off of the controller name as well as parameters passed from Rack such as the useragent string and ip address (here) 时才重要。因此,您必须在调用 Resque 作业之前解析这些值。

此时我的建议是实施一个 Resque class,它接受两个参数,一个 article_id 和您想要的印象参数。 resque class 将直接在易受影响的对象上创建印象。您的请求 class 将变为:

class ImpressionLogger 
  @queue = :impression_queue

  def self.perform(article_id, impression_params = {})
    article = Article.find(article_id)
    article.impressions.create(impression_params)
  end
end

你的控制器方法看起来像这样:

def show
  .
  .
  .
  Resque.enqueue(ImpressionLogger, @article.id, associative_create_statement({message: nil})) if unique_instance?(@article, [:session_hash])
end

免责声明

虽然这样做有一个相当大的免责声明......方法 associative_create_statement 被标记为受保护而 unique_instance? 被标记为私有......所以这些都不是印象派 gem 的 public API,因此此代码可能会在 gem.

的版本之间中断