Rails 4 - импрессионист внутри фоновой работы Resque

Я использую Rails 4 с импрессионистами и жемчужиной.

Я использую импрессионистов, чтобы регистрировать уникальные хиты сессий на моей странице показа статьи. Из-за проблем с производительностью и отсутствия необходимости отображать хиты для пользователей (это только для администраторов), я хотел бы перенести регистрацию показов в фоновом режиме.

Обычно я регистрирую показ, используя impressionist(@article, unique: [:session_hash]) но чтобы перенести его в bg через resque, я сейчас делаю что-то вроде этого...

articles_controller:

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

приложение / рабочие / 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, Как вы думаете, что лучший способ это сделать? Я не уверен, как включить импрессионистские методы в моего работника.

3 ответа

Решение

Проблема

Ваша проблема проистекает из того факта, что импрессионист работает на уровне контроллера из-за включения модуля с impressionist Метод в инициализаторе движка на любых экземплярах ActionController:

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

Вы пытаетесь вызвать метод импрессиониста из обычного класса, вызываемого в задании Resque, поэтому этот метод не будет определен.

Решение

Это довольно грубо, но если вы действительно хотите использовать импрессионистов, мы можем углубиться в это... Глядя на фактическую реализацию импрессионистского метода, найденную здесь, мы видим следующее:

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 кажется важной, только если вы хотите реализовать эту функцию. Что, похоже, так и есть. Призыв к associative_create_statement похоже, что параметры извлекаются на основе имени контроллера, а также параметров, передаваемых из Rack, таких как строка useragent и IP-адрес ( здесь). Таким образом, вам придется разрешить эти значения до вызова задания Resque.

На этом этапе я бы предложил реализовать класс Resque, который принимает два параметра, article_id и требуемые параметры показа. Тогда класс resque будет просто создавать впечатление на впечатлительный объект. Ваш класс Resque станет:

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? помечен как частный... так что ни один из них не является частью открытого API импрессионистского гема, поэтому этот код может разрываться между версиями гема.

Правильно ли установлен импрессионист в связке? В этом случае Rails должен загружать его в вашу среду. Я бы проверил, можете ли вы получить доступ impressionist функциональность в другом месте вашего кода Rails (т.е. без прохождения Resque) в качестве первого шага к отладке.

Как вы начинаете свои рабочие? Если вам нужна загруженная среда Rails, попробуйте rake environment resque:work,

https://github.com/resque/resque/wiki/FAQ

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