Кэш и ассоциации пользовательских Rails - перезаписывает ActiveRecord.find - PullRequest
4 голосов
/ 30 октября 2011

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

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

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

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

Когда я звоню X.find(1).children, я получаю Enumerator вместо 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 и т. Д., А более общее решение может поддерживать несколько классов моделей).

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

Ответы [ 2 ]

1 голос
/ 05 ноября 2011

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

Другие камни для просмотра: simple_cacheable

0 голосов
/ 05 ноября 2011

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

  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 (: все) ... это может помочь в вашей ситуации (или может не помочь) .

Возможно другое: Xcache возвращает только один ActiveRecord или возможно, что он иногда возвращает набор ... или даже пустой набор?

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

def self.find(*args)
    if args.size == 1 && args[0].is_a?(Numeric)
       rval = XCache[args[0]]
       return rval if rval.present?
    end
    super.find(*args)
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...