Ruby Forum Rails France > :has_many vers différents modèles

Posted by Liste diff (Guest)
on 06.01.2010 10:35
(Received via mailing list)
Bonjour,

J'ai besoin de votre aide pour un problème de conception.

Je veux faire une interface pour visualiser des logs de différentes 
sondes (relevé de température, d'humidité, sonde d'interruption). Les 
données sont transmises directement par les sondes dans plusieurs table 
MySQL (une table pour chaque type de logs). Comme les sondes elles-même 
ont toutes les même spécifications, j'ai créé une seule table pour les 
représenter.

J'ai donc un modèle Sensor qui possède plusieurs logs dans différents 
modèles (TemperatureLog, HumidityLog, etc.).

Ma question est comment puis-je, dans le modèle Sensor, indiquer dans 
quel modèle de Log (donc dans quelle table) aller chercher mes données. 
J'ai regardé du côté des associations polymorphiques, mais je ne suis 
pas sûr que ça puisse fonctionner dans ce sens.

Bref, vos avis ou votre aide et la bienvenue.

Merci d'avance,
Nicolas
Posted by Cyril Mougel (shingara)
on 06.01.2010 10:54
(Received via mailing list)
Le 06/01/10 08:23, Liste diff a écrit :
> Bref, vos avis ou votre aide et la bienvenue.
> 
> Merci d'avance,
> Nicolas
> 

Une des techniques simple est :

class TemperatureLog < SensorLog
end

class HumidityLog < SensorLog
end

class Sensor
  has_many :temperatures,
     :conditions => 'type = TemperatureLog',
           :class_name => "TemperatureLog",
           :foreign_key => "sensor_id"


  has_many :humidities,
     :conditions => 'type = HumidityLog',
           :class_name => "HumidityLog",
           :foreign_key => "sensor_id"
end
Posted by Liste diff (Guest)
on 07.01.2010 07:34
(Received via mailing list)
Merci Cyril de ta réponse, mais ce que j'aimerai faire est du genre:

@logs = sensor.logs

sans me soucier du genre de log à récupérer. Le choix de la table doit 
se faire automatiquement. Je n'ai pas de moyen de changer le schéma de 
la table des logs, mais je peux introduire un type de sonde.

Y-a-t'il une solution, en spécifiant le type de log dans mon modèle 
Sensor, de retrouver le modèle qui correspond au logs de la sonde 
spécifique?

Désolé pour ces questions sans doute basique, mais je suis novice en 
Rails.

Cordialement,
Nicolas


Le 6 janv. 2010 à 10:54, Cyril Mougel a écrit :
Posted by Cyril Mougel (shingara)
on 07.01.2010 11:10
(Received via mailing list)
Le 07/01/10 07:23, Liste diff a écrit :
> Merci Cyril de ta réponse, mais ce que j'aimerai faire est du genre:
> 
> @logs = sensor.logs
> 
> sans me soucier du genre de log à récupérer. Le choix de la table doit se faire automatiquement. Je n'ai pas de moyen de changer le schéma de la table des logs, mais je peux introduire un type de sonde.
> 
> Y-a-t'il une solution, en spécifiant le type de log dans mon modèle Sensor, de retrouver le modèle qui correspond au logs de la sonde spécifique? 
> 
> Désolé pour ces questions sans doute basique, mais je suis novice en Rails.
> 

Dans ce cas un simple has_many :logs suffit

class SensorLog < ActiveRecord::Base
end

class TemperatureLog < SensorLog
end

class HumidityLog < SensorLog
end

class Sensor
  has_many :logs,
           :class_name => "SensorLog",
           :foreign_key => "sensor_id"
end

Lorsque tu feras sensor.logs tu auras une liste de SensorLog
indépendamment de leur Type.

A tester, mais je crois même que le cast de la sous-classe se fait
automatiquement. Sinon, il suffit de faire une mini-méthode dans
SensorLog qui check le type et cast dans la bonne classe.
Posted by Liste diff (Guest)
on 07.01.2010 11:50
(Received via mailing list)
En fait je n'ai pas de modèle SensorLog.
J'aimerai pouvoir, directement à partir de mon modèle Sensor déterminer 
sur quelle modèle (TemperatureLog, HumidityLog, etc.) me connecter pour 
extraire les logs correspondant au type de sonde. Il me semble que ça 
doit pas être sorcier, mais je m'en sort pas. Je dois sans doute réviser 
les bases d'ActiveRecord ;-)

Nicolas


Le 7 janv. 2010 à 11:09, Cyril Mougel a écrit :
Posted by Cyril Mougel (shingara)
on 07.01.2010 12:02
(Received via mailing list)
Le 07/01/10 11:49, Liste diff a écrit :
> En fait je n'ai pas de modèle SensorLog. 
> J'aimerai pouvoir, directement à partir de mon modèle Sensor déterminer sur quelle modèle (TemperatureLog, HumidityLog, etc.) me connecter pour extraire les logs correspondant au type de sonde. Il me semble que ça doit pas être sorcier, mais je m'en sort pas. Je dois sans doute réviser les bases d'ActiveRecord ;-)
> 

HumidityLog et TemperatureLog sont dans la même table ou pas ?
Posted by Liste diff (Guest)
on 07.01.2010 12:39
(Received via mailing list)
Non, ce sont 2 tables séparées. Les logs sont directement générés par 
des sondes physiques. Les sondes de températures envoient leurs mesures 
de température à la table temperature_logs et les sondes d'humidité à 
humidity_logs. Il y a également d'autres sondes qui envoient d'autres 
valeurs.

L'application que je dois créer consiste à détecter les logs d'une sonde 
qui vient d'être mise en service et de permettre à l'utilisateur de 
donner un nom à cette sonde (dans la table sensors). Cette table est la 
même pour tous les logs, car les caractéristiques de toutes les sondes 
sont identiques.

Je veux ensuite pouvoir afficher les logs d'une sonde en faisant
logs = Sensor.find(1).logs
Dans la table sensors, je connais le type de sonde, je dois donc pouvoir 
faire une requête sur la bonne table. Malheureusement je ne maîtrise pas 
assez ActiveRecord et ruby pour savoir de quelle manière.

Merci de ton aide,
Nicolas

Le 7 janv. 2010 à 12:02, Cyril Mougel a écrit :
Posted by Cyril Mougel (shingara)
on 07.01.2010 12:45
(Received via mailing list)
Le 07/01/10 12:38, Liste diff a écrit :
> Non, ce sont 2 tables séparées. Les logs sont directement générés par des sondes physiques. Les sondes de températures envoient leurs mesures de température à la table temperature_logs et les sondes d'humidité à humidity_logs. Il y a également d'autres sondes qui envoient d'autres valeurs.
> 
> L'application que je dois créer consiste à détecter les logs d'une sonde qui vient d'être mise en service et de permettre à l'utilisateur de donner un nom à cette sonde (dans la table sensors). Cette table est la même pour tous les logs, car les caractéristiques de toutes les sondes sont identiques.
> 
> Je veux ensuite pouvoir afficher les logs d'une sonde en faisant 
> logs = Sensor.find(1).logs 
> Dans la table sensors, je connais le type de sonde, je dois donc pouvoir faire une requête sur la bonne table. Malheureusement je ne maîtrise pas assez ActiveRecord et ruby pour savoir de quelle manière.
> 

Dans ton cas il faut se palucher les requêtes à la main alors.

def logs
  humiditylogs + temperaturelogs
end

Bien sûr tu récupéreras tout d'un coup. Il faut donc gérer au cas pas
cas de tes besoins. Le schéma que tu as n'es pas adapté à ta logique. En
effet, tu as les même donnée dans des tables différentes. C'est donc de
la dé-normalisation. Je suis pour la dé-normalisation en terme de
performance, mais forcement, cela implique plus de code à écrire car la
dé-normalisation est comme elle l'indique, contraire au règle. Le
contraire au règle implique forcement une logique qui t'es personnel ou
tout du moins à ton cas précis.
Posted by Liste diff (Guest)
on 07.01.2010 14:07
(Received via mailing list)
Le 7 janv. 2010 à 12:44, Cyril Mougel a écrit :

> performance, mais forcement, cela implique plus de code à écrire car la
> dé-normalisation est comme elle l'indique, contraire au règle. Le
> contraire au règle implique forcement une logique qui t'es personnel ou
> tout du moins à ton cas précis.

Les tables de logs sont toutes différentes, avec un nombre de champs 
variable en fonction du type de sonde. Il me semble donc judicieux 
d'utiliser des tables différentes. Mais je peux me tromper et suis 
ouvert à une meilleure proposition.
Posted by Cyril Mougel (shingara)
on 07.01.2010 14:18
(Received via mailing list)
Le 07/01/10 14:06, Liste diff a écrit :
>> cas de tes besoins. Le schéma que tu as n'es pas adapté à ta logique. En
>> effet, tu as les même donnée dans des tables différentes. C'est donc de
>> la dé-normalisation. Je suis pour la dé-normalisation en terme de
>> performance, mais forcement, cela implique plus de code à écrire car la
>> dé-normalisation est comme elle l'indique, contraire au règle. Le
>> contraire au règle implique forcement une logique qui t'es personnel ou
>> tout du moins à ton cas précis.
> 
> Les tables de logs sont toutes différentes, avec un nombre de champs variable en fonction du type de sonde. Il me semble donc judicieux d'utiliser des tables différentes. Mais je peux me tromper et suis ouvert à une meilleure proposition.
> 

C'est judicieux en terme de performance. En terme de normalisation,
c'est pas évident. Ça dépend de ton cas.

Rails n'est qu'une aide a faire plus rapidement des cas plus ou moins
simple. Il ne faut pas forcement essayer de rentrer à tous les coups
dans le moule.
Posted by Liste diff (Guest)
on 07.01.2010 14:27
(Received via mailing list)
Ok, je vais voir quel est le design le plus approprié et j'adapterai mon 
code Rails en fonction.

Merci beaucoup pour ton aide et ta patience,
Nicolas

Le 7 janv. 2010 à 14:17, Cyril Mougel a écrit :