#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