Une partie de pourquoi j'aime Rails est que je déteste SQL - Je pense que c'est plus comme un langage d'assemblage qui devrait être manipulé avec des outils de niveau supérieur tels que ActiveRecord. Cependant, j'ai l'impression d'avoir atteint les limites de cette approche et je suis complètement dépassé par le SQL.Requêtes complexes sur les rails? sous-sélectionner? puis-je encore utiliser named_scope?
J'ai un modèle complexe avec beaucoup de sous-enregistrements. J'ai aussi un ensemble de 30-40 named_scopes qui implémentent la logique métier du client. Ces étendues sont enchaînées conditionnellement, c'est pourquoi j'ai ces étendues joins_
afin que les jointures ne soient pas tronquées.
J'ai quelques-uns d'entre eux qui ne fonctionnent pas correctement, ou du moins pas comment le client veut qu'ils travaillent. Voici une idée approximative de la structure du modèle, avec quelques portées nommées (pas toutes nécessaires pour l'exemple) qui illustrent mon approche et indiquent mes problèmes. (s'il vous plaît pardonner toutes les erreurs de syntaxe)
class Man < ActiveRecord::Base
has_many :wives
named_scope :has_wife_named lambda { |n| { :conditions => { :wives => {:name => n}}}}
named_scope :has_young_wife_named lambda { |n| { :conditions => { :wives => {:name => n, :age => 0..30}}}}
named_scope :has_yw_named_v2 lambda { |n| { :conditions => ["wives.name = ? AND wives.age <= 30", n]}}
named_scope :joins_wives :joins => :wives
named_scope :has_red_cat :conditions => { :cats => {:color => 'red'}}
named_scope :has_cat_of_color lambda { |c| { :conditions => { :cats => {:color => c}}}}
named_scope :has_7yo_cat :conditions => { :cats => {:age => 7}}
named_scope :has_cat_of_age lambda { |a| { :conditions => { :cats => {:age => a}}}}
named_scope :has_cat_older_than lambda { |a| { :conditions => ["cats.age > ?", a] }}
named_scope :has_cat_younger_than lambda { |a| { :conditions => ["cats.age < ?", a] }}
named_scope :has_cat_fatter_than lambda { |w| { :conditions => ["cats.weight > ?", w] } }
named_scope :joins_wives_cats :joins => {:wives => :cats}
end
class Wife < ActiveRecord::Base
belongs_to :man
has_many :cats
end
class Cat < ActiveRecord::Base
belongs_to :wife
end
Je peux trouver les hommes dont les femmes ont des chats qui sont rouges et sept ans
@men = Man.has_red_cat.has_7yo_cat.joins_wives_cats.scoped({:select => 'DISTINCT men'})
Et je peux même trouver des hommes dont les femmes ont les chats qui ont plus de 20 livres et plus de 6 ans
@men = Man.has_cat_fatter_than(20).has_cat_older_than(5).joins_wives_cats.scoped({:select => 'DISTINCT men'})
Mais ce n'est pas ce que je veux. Je veux trouver les hommes dont les femmes ont au moins un chat rouge et un chat âgé de sept ans, qui n'ont pas besoin d'être le même chat, ou de trouver les hommes dont les femmes ont au moins un chat au-dessus d'un poids donné et un chat plus âgé qu'un âge donné.
(dans les exemples suivants, s'il vous plaît supposer la présence dujoins_
etDISTINCT
approprié)Je peux trouver des hommes avec les femmes nommées Esther
@men = Man.has_wife_named('Esther')
Je peux même trouver des hommes avec les femmes nommées Esther, Ruth OR Ada (sweet!)
@men = Man.has_wife_named(['Esther', 'Ruth', 'Ada'])
mais je veux trouver des hommes avec des femmes nommées Esther ET Ruth ET Ada.
ha Ha, cela ne plaisante, en fait, je dois: Je peux trouver des hommes avec les femmes de moins de 30 nommé Esther
@men = Man.has_young_wife_named('Esther')
trouver des hommes avec des jeunes femmes nommées Esther, Ruth ou Ada
@men = Man.has_young_wife_named(['Esther', 'Ruth', 'Ada'])
mais comme ci-dessus je veux trouver des hommes avec de jeunes femmes nommées Esther AND Ruth AND Ada. Heureusement, le minimum est fixé dans ce cas, mais il serait bon de spécifier également un âge minimum.
est-il un moyen de tester une inégalité avec une syntaxe de hachage, ou avez-vous toujours de revenir à
:conditions => ["", n]
- noter la différence entrehas_young_wife_named
ethas_yw_named_v2
- J'aime le premier meilleur, mais la plage ne fonctionne que pour fini valeurs. Si vous cherchez une vieille femme, je suppose que vous pouvez utilisera..100
mais quand une femme a 101 ans, elle abandonne la recherche. (hmm.peut-elle cuisiner? j/k)Y at-il un moyen d'utiliser une portée dans une portée? Je serais ravi si
:has_red_cat
pouvait utiliser:has_cat_of_color
d'une façon ou d'une autre, ou s'il y avait un moyen d'utiliser la portée d'un enregistrement enfant dans son parent, donc je pourrais mettre les étendues liées au chat dans le modèleWife
.
Je ne veux vraiment pas faire cela dans SQL directement sans utiliser named_scope
, à moins qu'il ya quelque chose d'autre en fait plus agréable - suggestions pour les plugins et autres joyeusetés grandement appréciés, ou la direction dans le genre de SQL que je vais devoir apprendre. Un ami a suggéré que les UNIONs ou les sous-recherches fonctionneraient ici, mais celles-ci ne semblent pas être beaucoup discutées dans le contexte de Rails. Je ne connais pas encore les opinions - seraient-elles utiles? Y a-t-il une façon heureuse de les fabriquer?
Merci!
Comme j'allais St Ives
J'ai rencontré un homme avec sept femmes
Chaque femme avait sept sacs
Chaque sac avait sept chats
Chaque chat a sept kits
Kits, chats, sacs, femmes
Combien allaient à St Ives?
C'est une question vraiment intéressante dans l'abstrait. Et je comprends que vos noms de modèle et de portée sont dérivés d'une comptine. Mais c'est offensant, pour moi. Femme: appartient à l'homme? Sérieusement? –
ouais, j'ai pensé à ça quand je l'écrivais, mais le poème était apparu dans ma tête et je ne pouvais pas m'en débarrasser. –
Je voudrais trouver un bon moyen de faire 'UNION's dans les portées nommées en AR. Je sais que vous pouvez le faire dans SQLAlchemy. – mikelikespie