Requête sur : has_and_belongs_to_many

Bonjour,

Je voudrais faire une requête à partir de 2 tables dont voici les
modèles :

class Art < ActiveRecord::Base
has_and_belongs_to_many :artistes
end

class Artiste < ActiveRecord::Base
has_and_belongs_to_many :arts
end

L’idée serait de lister les arts, et pour chacun compter le nombre
d’artiste…
Pour les lister, j’avais écrit ceci dans un contrôleur :

@arts = Art.find(:all)

Et pour la vue, ceci :

<% for art in @arts -%>

<%=h art.name %>
<% end -%>

Par contre, je ne vois pas comment procéder pour mettre le nombre
d’artiste de l’art occurrent dans la balise

Merci pour vos idées.

Zang’

Bonjour,

tu peux essayer art.artistes.count ou art.artistes.size

Le 8 juin 08 à 10:45, Zangief I. a écrit :

Guillaume BELLEGUIC wrote:

tu peux essayer art.artistes.count ou art.artistes.size

Super! Merci beaucoup, ça fonctionne parfaitement bien. :slight_smile:

Ceci dit dans un soucis d’améliorer les performances tu devrais
peut-être
t’assurer de pré-loader ce compte pour éviter les aller-retours en base
de
données inutilement gourmands en temps de ressources disponibles.

Pour ce faire, deux solutions (il peut y en avoir plus, je ne cite que
celles qui me passent par la tête) :

  1. Art.find :all, :include => :artistes
    ca remplit directement tes objets “Art” avec les “Artistes”
    correspondants, tu n’as plus qu’Ã faire le “.count” ou “.size”
    c’est un peu lourd si tu n’as besoin que de les compter, mais ça
    marchera
  2. Art.count(:all, :group => ‘artiste’)
    cette dernière solution à l’avantage d’être plus légère en occupation
    mémoire et de déléguer à la base de données la tâche de faire le
    compte

A ta place et en supposant que j’ai bien compris ton problème c’est
cette
dernière que j’utiliserai pour optimiser la consommation de ressources
en
mémoire vive et en temps d’exécution ruby (les bases de données font
très
vite les comptes dans une requête group by, elles sont faites pour ça).

Pour le .count, rails envoie une requête select count(*) avec ou sans
:include, donc si il n’y a pas d’affichage à faire, ce n’est peut être
pas utile de faire un include (rails 2.0.2).en revanche pour le size
cela
doit être plus rapide.

2008/6/9 Michel B. [email protected]:

Probablement une bonne idée d’utiliser size si tu fais un “:include”.

Ceci dit, si tu as juste besoin de les compter, c’est un peu comme
utiliser
un lance-roquette anti-char pour tuer une mouche morte.

Zangief I. wrote:

Michel B. wrote:

  1. Art.find :all, :include => :artistes
    ca remplit directement tes objets “Art” avec les “Artistes”
    correspondants, tu n’as plus qu’Ã faire le “.count” ou “.size”
    c’est un peu lourd si tu n’as besoin que de les compter, mais ça
    marchera

Je viens d’essayer, et bizarrement Rails ne semble plus connaître la
méthode .count :
<% for art in @arts -%>

<%=h art.name %>
<%=h art.count %>
<% end -%>

NoMethodError in Artistes#index
undefined method `count’ for #Art:0x26023fc

Un tableau ne possède pas de méthode .count, pour un tableau, il faut
utiliser la methode .size

Michel B. wrote:

  1. Art.find :all, :include => :artistes
    ca remplit directement tes objets “Art” avec les “Artistes”
    correspondants, tu n’as plus qu’Ã faire le “.count” ou “.size”
    c’est un peu lourd si tu n’as besoin que de les compter, mais ça
    marchera

Je viens d’essayer, et bizarrement Rails ne semble plus connaître la
méthode .count :
<% for art in @arts -%>

<%=h art.name %>
<%=h art.count %>
<% end -%>

NoMethodError in Artistes#index
undefined method `count’ for #Art:0x26023fc

Merci pour votre aide. Je viens de tester avec .size, mais j’ai aussi
une erreur :
undefined method `size’ for #Art:0x249e7e0

C’est peut-être parce que je l’applique sur chaque élément du tableau
@arts, via ma vue.

Michel B. wrote:

Il faut l’appliquer à art.artistes si tu veux compter les artistes.

Wow, Merci beaucoup ! :smiley:
En regardant mon terminal, il y a bcp moins de requête en effet.
D’ailleurs je suis passé de 4 reqs/sec à 7 reqs/sec.

Ca risque d’être un problème quand tu scalera.

Essaye voir la méthode 2/ pour voir…

Il faut l’appliquer à art.artistes si tu veux compter les artistes.

Le 9 juin 2008 11:51, Michel B. a écrit :

Ceci dit dans un soucis d’améliorer les performances tu devrais peut-être
t’assurer de pré-loader ce compte pour éviter les aller-retours en base de
données inutilement gourmands en temps de ressources disponibles.

Pour ce faire, deux solutions (il peut y en avoir plus, je ne cite que
celles qui me passent par la tête) : (…)

À étudier :

http://eyedeal.team88.org/node/104

– Jean-François.


http://twitter.com/underflow_

Pour la méthode 2/ je vais essayer avec d’autres syntaxes, je te bippe
si /
quand je trouve la bonne.

Michel B. wrote:

Ca risque d’être un problème quand tu scalera.

Essaye voir la méthode 2/ pour voir…

Je viens d’essayer mais ça semble ne pas fonctionner. Voici l’erreur
affichée par Rails :

ActiveRecord::StatementInvalid in Artistes#index
Showing layouts/application.html.erb where line #100 raised:
Mysql::Error: #42S22Unknown column ‘artiste’ in ‘field list’: SELECT
count(*) AS count_all, artiste AS artiste FROM arts GROUP BY
artiste

Voici aussi ce que j’ai dans mon application :

module ArtistesHelper
def art_practiced
# Méthode 1 :
# @arts = Art.find :all, :order => :name, :include => :artistes

# Méthode 2 :
@arts = Art.count(:all, :group => 'artiste')

render :partial => 'arts/listing'

end
end

En tout cas la 1ère solution fonctionne très bien et a parfaitement
réglée mon souci :slight_smile: