Пользовательский кеш Rails и ассоциации — перезапись ActiveRecord.find

#ruby-on-rails

#ruby-on-rails

Вопрос:

Я хочу написать пользовательский кеш ActiveRecord, только на find_by_id данный момент. Для этого я хочу перезаписать метод find, когда задается только один int, используя мой кеш, в противном случае используйте реализацию по умолчанию.

 class X < ActiveRecord::Base
    def self.find(*args)
        return XCache[args[0]] if args.size == 1 amp;amp; args[0].is_a?(Numeric)
        return super.find(*args)
    end
end
 

Все работает find, за исключением случая ассоциации, которая у меня есть с другими экземплярами X, например, отношения родитель-потомок:

 has_many :x_children
has_many :children, :class_name => "X", :through => :x_children
 

Когда я вызываю X.find(1).children , я получаю Enumerator вместо an Array , что плохо, поскольку я иногда использую оператор [] .

Даже использование перечислителя работает плохо — при повторении последней записи я получаю:

 NoMethodError: undefined method `call' for :all:Symbol
 

Любая помощь будет высоко оценена

Дальнейшее объяснение:

XCache — это просто класс, который кэширует экземпляры ActiveRecord. Упрощенная реализация может быть

 class XCache
    @@cache = {}
    def self.[id]
        return @@cache[id] ||= X.find(id)
    end
end
 

(Более продвинутая реализация может включать время истечения срока действия, Memcached и т. Д., А более общее решение может поддерживать несколько классов моделей).

Я не думаю, что моя проблема связана с реализацией кэша (но я могу ошибаться)

Комментарии:

1. Чего именно вы хотите здесь добиться? Библиотека общего назначения или решение конкретной проблемы?

2. Не могли бы вы объяснить, что XCache это такое? Я искал в Интернете, но ничего не нашел. Если вы реализовали самостоятельно (и если это не слишком много кода), просто добавьте этот код в свой вопрос.

3. не знаю, помогает ли это, но факт в том, что Active Record кэширует связанные записи по умолчанию

Ответ №1:

Как вы видели, здесь много скрытых сложностей. Вы могли бы заглянуть в драгоценный камень cache-money, эти ребята потратили много усилий, выясняя это.

Другие драгоценные камни, на которые стоит обратить внимание: simple_cacheable

Ответ №2:

Не уверен, поможет ли это, но… Вот как выглядит find изнутри:

   def find(*args)
    options = args.extract_options!
    validate_find_options(options)
    set_readonly_option!(options)

    case args.first
      when :first then find_initial(options)
      when :last  then find_last(options)
      when :all   then find_every(options)
      else             find_from_ids(args, options)
    end
  end
 

Вам не нужно перегружать «find», но «find_from_ids»

Это позволит вам оставить в покое все другие способы использования find и просто настроить таргетинг на ваше собственное использование.Учитывая, что перечислители — это то, что возвращается find(:all) … это может помочь вашей ситуации (а может и нет).

Другая возможность заключается в том, что … возвращает ли Xcache только один ActiveRecord или возможно, что он иногда возвращает набор … или даже пустой набор?

Возможно, вы могли бы попробовать варианты:

 def self.find(*args)
    if args.size == 1 amp;amp; args[0].is_a?(Numeric)
       rval = XCache[args[0]]
       return rval if rval.present?
    end
    super.find(*args)
end