2009-10-04 4 views
2

Pour des raisons un peu compliqué, je voudrais créer quelque chose qui fonctionne comme ceci:Où patcher Rails ActiveRecord :: find() pour d'abord vérifier les collections en mémoire?

# Controller: 
@comments = @page.comments # comments are threaded 
# child comments still belong to @page 
... 
# View: 

@comments.each_root { 
    display @comment { 
    indent & recurse on @comment.children 
} } 

# alternatives for how recursion call might work:  

# first searches @comments, then actually goes to SQL 
comment.in_memory.children 

# only looks at @comments, RecordNotFound if not there 
# better if we know @comments is complete, and checking for nonexistent 
# records would be wasteful 
comment.in_memory(:only).children 

# the real thing - goes all the way to DB even though target is already in RAM 
# ... but there's no way for find() to realize that :(
comment.children 

Je ne suis même pas encore sûr si cela est possible, et encore moins une bonne idée, mais je suis curieux, et ce serait utile.

Fondamentalement, je veux rediriger find() afin qu'il regarde d'abord/seulement à la collection qui a déjà été chargé, en utilisant quelque chose comme un hypothétique @collection.find{|item| item.matches_finder_sql(...)}.

Le but est d'empêcher la mise en cache inutilement complexe et les recherches de base de données coûteuses pour des éléments qui ont déjà été chargés en masse.

Si possible, ce serait bien si cela a joué agréable avec des mécanismes existants pour caducité, association chargement paresseux, etc.

La chose emboîtées commentaires est juste un exemple; Bien sûr, cela s'applique à beaucoup d'autres situations aussi.

Alors ... comment est-ce que je pourrais faire ceci?

Répondre

1

Vous ne devriez pas écrire quelque chose qui est déjà dans Rails lui-même! Vous pouvez facilement tirer parti des méthodes de mise en cache de Rails pour mettre les résultats de la requête dans Memcached (ou quel cadre la mise en cache jamais vous avez configuré):

class ArticleController < ApplicationController 
    def index 
    @articles = Rails.cache(:articles_with_comments, :expires_in => 30.minutes) do 
     Article.find(:all, :include => :comments) 
    end 
    end 
end 

BTW. le :expires_in est optionnel. Vous pouvez laisser le cache 'pour toujours' ou l'expirer manuellement.

exemple Deuxièmement, comme mon commentaire:

class ArticleController < ApplicationController 
    def index 
    @page = Page.find(params[:page_id] 

    @articles = Rails.cache([:articles_with_comments, @page.id], :expires_in => 30.minutes) do 
     Article.find(:all, :include => :comments, :conditions => { :page_id => @page.id}) 
    end 
    end 
end 

Cela cache les articles et commentaires pour un objet @page donné.

+0

En bonus, vous pouvez utiliser un tableau pour la clé cache. Cette clé peut inclure des variables "dynamiques". J'ai ajouté un deuxième exemple. – Ariejan

+0

Cela ne fait pas ce que je veux, car il ne me permet pas de continuer à utiliser les méthodes standard find et using-using (comme .children de awesome_nested_set). Le problème n'est pas un problème de mise en cache (comme ce que vous abordez) mais plutôt un problème de proxy. – Sai

Questions connexes