2009-07-02 4 views
8

Je me demande s'il existe un moyen efficace de combiner les résultats de plusieurs objets ActiveRecord dans Rails. Par exemple, je pourrais faire trois appels individuels à trois tables individuelles, et je veux que les résultats soient combinés, et triés par une colonne commune.Comment combiner des objets ActiveRecord?

Voici un exemple super code de base qui nous l'espérons rendre ma question plus facile à comprendre:

@results1 = Table1.find(:all) 
@results2 = Table2.find(:all) 
@results3 = Table3.find(:all) 

@combined_results_sorted_by_date_column = (how?) 

Comme suggéré par d'autres, voici une solution au problème. Que faire si je veux trier par date, mais que Table3 fait référence à la colonne "created_on" en tant que date?

Répondre

2

Vous ne travaillez pas avec des "tables" mais des objets.

Si vous pensez de cette façon, il ne serait pas logique d'avoir:

@results1 = Users.find(:all) 
@results2 = Posts.find(:all) 
@results3 = Comments.find(:all) 

Quelle serait la forme « combinée » de cela signifie?

Ce que vous voulez probablement est de combiner des résultats du même genre en utilisant différentes "requêtes". Est-ce cela?

+0

Je dispose d'un cas d'utilisation, de commentaires, de statuts et de validations combinés pour un scénario dans une application de gestion des problèmes. – dangerousdave

+0

Dans ce cas, ils doivent tous répondre à une interface spécifique ou avoir un moyen d'être mappés en un. Le point clé est que le fait d'y penser en termes de «tables de base de données» va vous mener vers de mauvaises conceptions. Je n'essayais pas d'insinuer que vous n'utilisiez pas les données provenant de différents endroits, juste en vous demandant comment vous abordez/pensez à ce sujet. –

0
@combined_results = @result1 + @result2 + @result3 
@combined_results.sort! {|x,y| x.date <=> y.date} 

Bien que ce ne soit sûrement pas le code le plus efficace au monde, il pourrait bien être ce dont vous avez besoin.

Si certains modèles n'ont pas de méthode de date, je vous suggère d'en créer un. C'est aussi simple que.

def date 
    created_on 
end 
0
@results1 = Table1.find(:all) 
@results2 = Table2.find(:all) 
@results3 = Table3.find(:all) 

combined = (@results1 + @results2 + @results3).sort { |x, y| x.date <=> y.date } 
+0

Que faire si je veux trier par date, mais Table3 fait référence à la colonne "created_on" comme date? Grand merci! – Jess

+0

Vous pouvez résoudre cela en ajoutant une méthode "date()" à Table3 qui renvoie la valeur de "created_on". – Ethan

14
@results1 = Table1.find(:all) 
@results2 = Table2.find(:all) 
@results3 = Table3.find(:all) 

@combined_results_sorted_by_date_column = 
    (@results1 + @results2 + @results3).sort_by(&:date) 

si je veux trier par date, mais Table3 fait référence à la colonne "created_on" comme la date?

class Table3 
    alias_method :date, :created_on 
end 

ou simplement

class Table3 
    alias date created_on 
end 
0

Je ne suis pas sûr de ce que vos volumes de données sont comme, mais en ce qui concerne le tri, la base de données fera un meilleur travail que vous avez jamais vous en utilisant " code de la couche applicative ".

Avez-vous besoin les données renvoyées comme un tableau d'objets de modèle car les trois tableaux sera probablement générer un tableau mixte de trois classes de modèles distincts?

Pourquoi ne pas utiliser des lignes et des colonnes de retour directe SQL et ont la DB faire tout le travail de tri des données?

1

Vous n'apprécierez probablement pas cette réponse, mais je dirais que vous voudrez peut-être réviser votre schéma de base de données. J'étais dans une situation similaire, et trier les résultats après les concaténer n'est certainement pas la façon dont vous voulez aller.

+1

Je vous crois, mais pourriez-vous être plus précis sur la façon dont vous avez géré la situation? – iterion

0

Je suppose que vous voulez un tableau mixte de trois différents types d'objets ActiveRecord, triées par date quelconque.

@array = (Bucket.all + Mop.all + Detergent.all).sort{|x,y| x.sort_by <==> y.sort_by} 

Puisque votre champ sort_by est différent pour chaque type d'objet, vous devez le définir.

class Bucket < ActiverRecord::Base 
    def sort_by 
    cleaned_on 
    end 
end 

class Detergent < ActiverRecord::Base 
    def sort_by 
    purchased_on 
    end 
end 

Vous pouvez tirer dans toutes les données triées en une seule requête en utilisant UNION, mais vous n'obtenir des objets AR de cela.

Questions connexes