2009-07-17 3 views
6

Impossible de trouver celui-ci. Dans le modèle rails, je souhaite appeler une méthode dans le même modèle pour manipuler les données renvoyées par une méthode find. Cette méthode 'filter' sera appelée à partir de nombreuses méthodes de recherche personnalisées dans ce modèle, donc je veux qu'elle soit séparée. (Et je ne peux pas filtrer du SQL est trop compliqué)Rails: méthode d'appel dans le modèle

Voici un exemple:

#controller 
@data = Model.find_current 

#model 
class Model 
    def self.find_current 
    @rows = find(:all) 
    filter_my_rows 
    return @rows 
    end 

    def filter_my_rows 
    #do stuff here on @rows 
    for row in @rows 
     #basically I remove rows that do not meet certain conditions 
    end 
    end 
end 

Le résultat de ceci est: méthode non définie filter_my_rows'

Merci pour toute aide!

Répondre

4

Une partie du problème est que vous définissez une méthode de classe appelée find_current et une méthode d'instance appelée filter_my_rows. Généralement, vous les définissez tous les deux dans le même cadre pour qu'ils puissent travailler ensemble.

Une autre chose est que vous pouvez faire beaucoup de filtrage dont vous avez besoin avec un simple appel Array # reject. Par exemple:

@models = all.reject do |m| 
    # This block is used to remove entries that do not qualify 
    # by having this evaluate to true. 
    !m.current 
end 

Vous pouvez modularisation cela un peu en branchant des fonctions selon les besoins, aussi, mais qui peut se sauvagement compliquée à gérer si vous ne faites pas attention.

# Define reusable blocks that are organized into a Hash 
CONDITION_FILTERS = { 
    :current => lambda { |m| m.current } 
} 

# Array#select is the inverse of Array#reject 
@models = all.select(CONDITION_FILTERS[:current]) 

Alors que vous avez dit dans votre question que cela n'a été nécessaire en raison de préoccupations au sujet de ne pas être en mesure de déterminer la pertinence d'un dossier particulier avant que tous les enregistrements sont chargés de la base de données, c'est la forme généralement mauvaise puisque vous va probablement rejeter une grande quantité de données que vous avez eu la peine de récupérer et d'instancier comme modèles seulement pour les jeter immédiatement.

Si possible, vous devez au moins mettre en cache les lignes extraites pendant la durée de la demande afin de ne pas devoir continuer à les récupérer à plusieurs reprises.

+0

Cela a fonctionné pour moi en partie. Je ne comprends pas complètement lambda, je vais devoir lire dessus, mais la méthode de rejet sera très utile pour enlever des lignes du tableau de recherche. Merci – mickey

2

utiliser un named_scope à la place

named_scope :current, :conditions => {:active => true} # this is normal find criteria 

puis dans votre contrôleur

@date = Model.current 

vous pouvez également les fonctions named_scopes lambda

+1

Merci, mais je (ne pense pas) pouvoir utiliser la portée ou tout filtrage de condition pour le SQL car les conditions que j'ai besoin de vérifier proviennent de données provenant de bases de données différentes (sur différents serveurs). Donc, je dois les boucler et les vérifier un par un sur l'association belongs_to elle-même. – mickey

0

Quel est le problème avec vos solutions? Que recherchez-vous exactement? Si je comprends bien votre point de vue, le problème principal de votre mise en œuvre est que

This 'filter' method will be called from many custom find method within this model, so I want it to be separate.

... que vous ne pouvez pas utiliser named_scopes ou with_scope, la première solution qui vient à l'esprit est de créer une coutume wrapper pour agir comme un filtre.

class Model 
    def self.find_current 
    filtered do 
     all 
    end 
    end 

    def self.other_method 
    filtered do 
     all :conditions => { :foo => "bar" } 
    end 
    end 

    def self.filtered(&block) 
    records = yield 
    # do something with records 
    records 
    end 

end 
+0

Quel est le problème avec ma méthode est qu'il me donne cette erreur: méthode non définie 'filter_my_rows '. Tout comme si elle n'était pas capable de comprendre que j'essaie d'appeler une méthode de l'intérieur de lui-même. Votre méthode me donne également la même erreur: méthode non définie 'filtrée ' – mickey

+0

J'ai corrigé l'erreur. La méthode doit être auto-filtrée. –

3

La fonction de classe et la fonction de l'instance est votre problème.

Vous ne pouvez pas appeler une fonction d'instance dans votre fonction de classe de cette façon. Utilisez self.filter_my_rows pour définir votre fonction (notez le self) et tout ira bien.

Questions connexes