2009-10-20 5 views
3

L'arrière-plan de ce problème est assez complexe et compliqué, et comme je cherche une réponse simple, je vais laisser le problème de côté pour expliquer mon problème, et fournir cette situation hypothétique.ActiveRecord named_scope, .scopes

Si j'ai un modèle simple ActiveRecord appelé Automobile, avec named_scopes comme ci-dessous:

named_scope :classic, :conditions => { :build_date <= 1969 } 
named_scope :fast, lambda { |speed| :top_speed >= speed } 

Ignorant les champs eux-mêmes, si je devais appeler:

Automobile.scopes 

Que serait exactement ce retournerait ? Ce que je vois dans la console est:

[ :classic => #<Proc:[email protected]/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87>, 
    :fast => #<Proc:[email protected]/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87> ] 

Cela me semble être un tableau de valeurs clés /, la clé étant le symbole de la portée du nom, et la valeur étant un Proc pointant vers le named_scope.rb fichier dans ActiveRecord.

Si je veux le hachage ou Proc donné que la portée réelle du nom (qui signifie pour: classique, je recevrais « : conditions => {: build_date < = 1969} », ​​comment pourrais-je faire pour trouver ce

?

Je vous écris un plugin conditionnel se confond quelques named_scopes, et je me présente contre une certaine résistance en ce qui concerne ce J'utilise actuellement ce qui suit pour fusionner ces champs d'application:.

scopes_to_use = Automobile.scopes 
scoped_options = {} 
Automobile.scopes.each do |scope| 
    scoped_options.safe_merge!(eval "Automobile.#{scope}(self).proxy_options") 
end 

Ignorant la « justesse » de ce que je fais ici, y at-il une meilleure façon que je puisse récupérer le hachage réel ou Proc donné à named_scope? Je n'aime pas utiliser 'eval' dans cette fonction, et si je pouvais récupérer le Hash ou le Proc, je serais capable d'introduire une logique de fusion beaucoup plus puissante. Toutes les pensées à ce sujet seraient très appréciées. Merci. Les portées nommées que vous définissez dans votre exemple ne feraient rien.

Répondre

2

Ils sont syntaxiquement erronés. Cela pourrait causer des problèmes.

En supposant que les exemples ont été créés à la hâte et que vous avez des travaux. Sur la réponse.

Comment rechercher le hachage ou le nom de processus donné en tant que portée nommée réelle.

Model.scopes[:scope_name] vous donne le proc. Model.send(:scope_name).proxy_options vous donne les options hachage données à la portée à savoir: { :conditions => ["build_date <= ?", 1969] }

Pour récupérer programatically le hachage des options de chaque champ nommé dans un modèle que vous pouvez faire ceci:

scopes_to_use = Automobile.scopes 
scoped_options = {} 
Automobile.scopes.keys.each do |scope| 
    scoped_options.safe_merge!(Automobile.send(scope).proxy_options) 
end 

Cela ne fonctionne pas comme joliment pour les étendues qui nécessitent des arguments, car ils pourraient soulever des exceptions. Malheureusement, je ne peux pas imaginer un moyen simple de contourner cela. Le meilleur que je peux arriver avec est de tester l'arité de la proc, puis fournir des arguments fictifs uniques et analyser les options de proxy retournées pour comprendre ce qui a changé. Mais c'est beaucoup de travail, car l'arité de toute portée nommée est de -2. Le mieux que vous puissiez faire en récupérant l'arité est d'appeler le proc, de sauver une erreur d'argument et de l'analyser pour le nombre ou les arguments attendus. Ensuite, utilisez ce nombre d'arguments factices.

L'ensemble du processus nécessite un bloc de secours et un peu de magie Eval pour fonctionner. Et c'est avant que vous pouvez traiter le hachage proxy_options pour votre fusion sécurisée.

En bref, vous aurez envie de faire quelque chose proche de cela, ce n'est pas jolie, mais il fonctionne:

scopes_to_use = Automobile.scopes 
    scoped_options = {} 
Automobile.scopes.each do |scope,proc| 
    next if scope == :scoped 
    number_of_args = 1 
    begin 
    scoped_options.safe_merge! Automobile.send(scope, "#{scope}_argument_1").proxy_options 
    rescue 
    $!.to_s.match /(\d+)\)$/ 
    number_of_args = $1.to_i 
    puts number_of_args 
    end 
    scoped_options.safe_merge!(Automobile.send(scope, *(1..number_of_args).map{|i| "#{scope}_argument_#{i}"}.proxy_options) 
end 

Ce qui devrait être en sécurité parce que proxy_options n'exécute pas le SQL ni ne font aucune vérification de type .

+0

Cette solution semble viable, mais elle est plutôt plus intensive que je ne le voudrais à ce stade. Je cherchais quelque chose de disponible directement via l'API de rails que j'avais peut-être manqué, mais si rien n'existe exactement, alors je pense que je préférerais trouver une autre solution à mon problème global qu'une question discutable utilisant des portées nommées. Merci pour votre réponse. Il a certainement répondu à ma question, mais a également soulevé un peu plus pour moi. Si la solution est si complexe, alors mon but doit être faux. – Synthlabs

+0

Ce n'est pas important à ce stade, mais j'ai appris l'existence de l'opérateur *. J'ai édité la solution pour l'utiliser à la place de l'eval. – EmFi

+0

J'ai rencontré le même problème, c'est triste que la seule solution est la suivante. –

Questions connexes