2017-10-09 2 views
1

J'ai une relation has_many, through: entre Projets et Catégories à l'aide d'un modèle de catégorisation. Un projet belongs_to a Client.Requête de regroupement avec plusieurs relations dans les rails

class Client < ApplicationRecord 
    has_many :projets 
end 

class Category < ApplicationRecord 
    has_many :categorizations, dependent: :destroy 
    has_many :projets, through: :categorizations 
end 

class Categorization < ApplicationRecord 
    belongs_to :category 
    belongs_to :projet 
end 

class Projet < ApplicationRecord 
    belongs_to :client 
    has_many :categorizations, dependent: :destroy 
    has_many :categories, through: :categorizations 
end 

Pour une catégorie spécifique, j'aimerais énumérer tous les projets, regroupés par le client. par exemple.

(pour category_id = 3)

Client A Projet 1 Projet 2

client B Projet 3

client C Projet 4

Jusqu'à présent, je peux obtenir ce travailler, mais seulement en utilisant deux requêtes (dont une très inefficace (problème n + 1)

Ce code

def listing 
    @projets_clients = Projet 
    .select("client_id") 
    .includes(:client) 
    .joins(:categorizations) 
    .where(categorizations: { category: @category }) 
    .group("client_id") 

    @clients = [] 
    @projets_clients.each do |p| 
    @clients << Client.includes(:projets).find(p.client_id) 
    end 
end 

Si quelqu'un peut suggérer une meilleure approche que j'aimerais apprendre comment optimiser ce que je ne l'ai pas été en mesure de trouver une meilleure façon moi-même.

Merci.

Répondre

1

Il y a plusieurs façons de procéder. Pour les requêtes complexes, il m'est parfois plus facile d'écrire et d'exécuter du SQL direct. Cependant, pour votre cas, en fonction de la taille des données, vous pouvez simplement charger les données et les transformer en hash.

Remarque: Lorsque je testais ce code, j'ai utilisé projects au lieu de projets.

@category = Category.includes(projects: [:client]).find(2) 
@projects_by_client = @category.projects.group_by(&:client_id) 

# In your view 
<%- @projects_by_client.each do |client_id, projects| %> 
    <%= projects.first.client.name %> 
    <%- projects.each do |project| %> 
    <%= project.name %> 
    <% end %> 
<% end %> 

Une solution plus élaborée peut utiliser SQL complet avec un objet de requête et un objet de présentation. J'ai créé un projet rapide en utilisant le code ci-dessous et la sortie est ce que vous cherchez. Ceci est bien sûr l'une des nombreuses façons d'obtenir vos données dans une seule requête et de les présenter.

+0

Wow, merci beaucoup pour la réponse détaillée! L'approche SQL est vraiment intéressante. Désolé pour la confusion avec les projets. Le code dans votre premier exemple a cependant une petite erreur, mais grâce à votre aide généreuse (comment imbriquer inclut!), Je pense que j'ai trouvé ce que c'était: @projects_by_client = @ category.projects.group_by (&: client_id) (besoin d'ajouter le .projects aussi - et la ligne '@clients =' est aussi trop je pense) Peut-être qu'il serait utile pour les autres de mettre à jour ce et puis je peux le marquer comme la bonne réponse? Maintenant, cela fonctionne parfaitement, merci beaucoup! – Chris

+1

J'ai mis à jour le code pour corriger les erreurs que vous avez remarquées. – Genzume