Dynamic act_as

Bonjour,

est-il possible d’attribuer des plugin act_as de manière dynamique à des
objets et non des classes via les metaclass ou autre chose… ?

sinon, est ce quelqu’un saurait comment faire pour créer des relations
rails directement sur un objet et non sa classe de façon à avoir des
objets avec des relations différentes les uns des autres ?

merci.

Bien sûr, avec des modules en utilisant extend :

module ActAsEnrhume
def eternue
p “a… a… a… A… ATCHOUM !”
end
end

o = Object.net
o.extend ActAsEnrhume

o.eternue

merci pour la réponse.
Dans ce cadre relativement simple, je sais faire.
Par contre, si je veux que mon objet inclut une relation has_one par
exemple (donc que les autres objets de la même classe n’auront pas),
comment puis je faire ?

merci.

Ah. Là c’est un problème de persistance en base de données que tu te
pose,
pas un problème de langage ruby.

Pour que ta relation persiste en base de données il faut que la table de
données de ta base ait les champs nécessaires pour faire les liaisons lÃ
où
on en a besoin.

Comme je ne sais pas quel est ton problème précis ici, et j’aurais
besoin de
le cerner pour pouvoir répondre à ta question. Cependant, à mon avis, tu
ferais bien de chercher plutôt dans les associations polymorphiques, il
me
semble ça ressemble beaucoup plus à ce que tu cherches à faire.

effectivement, j’y songeais, mais dans le doute d’avoir la bonne
solution (que je n’ai pas encore), je pose la question :wink:

l’idée est simple:
j’aime le principe du acts_as. Je trouve ça facile à développer et Ã
mettre en place.

Donc, imaginons que j’ai une classe Stylo et que certains stylos peuvent
avoir une gomme ou non, 2 couleurs ou non etc etc, des espèces de
composants de personnalisation, je voudrais pouvoir faire:

stylo1 = Stylo.new

stylo2 = Stylo.new

stylo1.acts_as_multicouleurs #=> imaginons que ce soit faisable…
stylo1.ecrire_en_bleu #=> méthode du module acts_as_multicouleurs
stylo1.acts_as_gomme #=> imaginons que ce soit faisable…
stylo1.efface_derniere_ligne #=> méthode du module acts_as_gomme

stylo2.ecrire_en_bleu # => erreur car stylo2 n’est pas multicouleurs
stylo1.efface_derniere_ligne # => idem…

stylo1.save #=> et là je sauvegarde le fait que mon stylo1 est un objet
de type Stylo mais avec ses différents composants : il a une gomme et
peut écrire en bleu, et disons que un gommage a supprimé 1% de ma gomme
(donc il faut que je stocke l’information, d’où l’idée du acts_as pour
le stockage persistant). Et donc la prochaine fois que j’initialise mon
objet, il faut que rails me regénère l’objet complet en mémoire avec
toutes ses méthodes et ses propriétés

voila l’idée en gros… Est ce plus claire ? Si tu as une solution ou
une piste, je suis preneur!!! ;)))))

C’est pas beaucoup plus clair…

Essaye plutôt de me dire à quoi ça pourrait servir dans la vrai vie,
parce
que l’histoire des stylos ça me semble un peu sorti d’un chapeau.

en fait c’est un système de composants dynamiques, avec stockage
persistant pour certains d’entre eux (donc table associée à l’objet)
pour personnaliser les objets d’une classe de manière unique à chaque
fois, et en live, sans avoir à modifier le code source de l’application

un autre exemple :
une classe téléphone : Telephone
certains téléphone sont wifi et d’autres analogiques, mobiles ou fixe,
avec des unités de temps ou non etc etc…

telephone1 = Telephone.new
telephone2 = Telephone.new

telephone1.acts_as_analogique # => ajoute toutes les fonctionnalités
d’un téléphone analogique à cet objet téléphone

et donc maintenant je peux utiliser les fonctionnalités ajoutées par le
module acts_as_analogique, par exemple:
telephone1.passer_appel_analogique

telephone2.acts_as_wifi # => ajoute toutes les fonctionnalités d’un
téléphone wifi à cet objet téléphone
telephone2.detecter_borne_wifi #=>méthode ajoutée par le plugin
acts_as_wifi
telephone2.passer_appel_wifi if telephone2.has_wifi_access #=>méthodes
ajoutées par le plugin acts_as_wifi

est ce que ça te parle plus maintenant ?

ok,

merci pour tous ces conseils, je vais essayer de voir dans cette
direction un peu plus alors.

En gros, tu veux pouvoir stocker des objets avec des relations
arbitraires
entre eux.

Dans ce cas, à ta place, je penserais sérialisation pour stocker des
objets
arbitraires dans une table de stockage et polymorphisme pour faire le
lien
entre tes objets.

Charlie Charlie a écrit :

stylo1.efface_derniere_ligne # => idem…
une piste, je suis preneur!!! ;)))))

Moi je trouve que la solution d’écrire dans des modules et d’utiliser
ensuite extend correspond parfaitement à tes besoins.
module Multicouleur
def ecrire_en_bleu
p “j’écris en bleu”
end
def ecrire_en_rouge
p"j’écris en rouge"
end
end

stylo1 = Stylo.new

stylo.extend Multicouleur

Cependant j’ai l’impression que tu veux utiliser des modules dont tu
n’est pas l’auteur (plugin), dont le comportement est déjà prédéfini
(Ils ajoutent des méthodes à ActiveRecord, et encore plus à la classe
qui appelle acts_as). Ce comportement ne te satisfais pas, car tu ne
voudrais pas inclure systématiquement les méthodes à tous les objets de
la classe.
Regarde bien le code du plugin “acts_as” qui t’intéresse, il ne fait
qu’ajouter des méthodes(de classe ou d’objet) à ActiveRecord. Un appel Ã
acts_as va ajouter des méthodes à la classe qui l’appelle, et aux objets
instances de cette classe. Une petite adaptation sera donc nécéssaire
(il va falloir que tu triffouille le code du plugin).

Souvent le code de ces plugins est séparé en deux modules: le module
“ClassMethods” et le module “InstanceMethods”.

Il te suffit donc de le laisser charger le module “ClassMethods” (pour
étendre les méthodes de class), mais pas le module InstanceMethods.
Celui là tu l’incluera au cas par cas avec
stylo1.extends(ActsAsBlabla::InstanceMethods)

Seb

seb

le problème c’est la persistance associée à l’objet.
Comment ajouter une relation has_one avec un extend mais juste sur
l’instance en question et non pas la classe ?

Avec une association polymorphique justement.

Michel B. wrote:

Avec une association polymorphique justement.

si tu as un exemple, je suis preneur, car je ne vois pas comment…

là je suis plutôt en train de découper le code de active record pour
voir comment modifier has_one et le rendre compatible pour une instance.
Ce qui n’est sûrement pas le plus simple, mais bon…

Heu, oui, enfin, découper le code d’AR c’est probablement pas le plus
simple, mais bon, tu fais comme tu veux aussi…

Pour les associations polymorphes, plus qu’un exemple incompréhensible,
voici une explication de ce que c’est et à quoi ça sert :
http://wiki.rubyonrails.org/rails/pages/UnderstandingPolymorphicAssociations

Michel B. wrote:

Heu, oui, enfin, découper le code d’AR c’est probablement pas le plus
simple, mais bon, tu fais comme tu veux aussi…

Pour les associations polymorphes, plus qu’un exemple incompréhensible,
voici une explication de ce que c’est et à quoi ça sert :
http://wiki.rubyonrails.org/rails/pages/UnderstandingPolymorphicAssociations

ha! je connais les associations polymorphiques, je les utilise souvent.
effctivment je peux faire

MaClassPrincipale
has_many :composants
end

composants étant polymorphique
mais si je fais un

has_one composantX, :throught composants

dans le code du module, cela va affecter toute la classe, non ?

Je me demande pourquoi tu es aussi obsédé par les modules. Il y a une
raison
particulière ?

Michel B. wrote:

Je me demande pourquoi tu es aussi obsédé par les modules. Il y a une
raison
particulière ?

oui avoir des objets tous de la même classe mais personnalisés
dynamiquement.
En gros, il faut que via un BO un administrateur puisse injecter dans
l’application des nouveaux objets avec des comportements différents les
uns des autres, tout ça sans redémarrer l’application ni changer une
ligne de code.
Et une fois ces objets lâcher dans l’application il faut que je puisse
sauvergarder l’état de chacun avec l’état de l’ensemble de leur
composants, tout ça pour pouvoir, quand l’application s’arrête recharger
tous les objets avec leur dernier état connu.

Admettons qu’on arrive à faire ce que tu veux tel que tu le veux (avec
des
modules, à mon avis c’est pas gagné), ça veut aussi dire que une fois un
comportement attribué à un objet, impossible de le retirer à l’objet
(sauf
si tu me trouve comment en Ruby on peut retirer des modules à un objet ;
je
ne suis pas sûr que ça n’existe pas, je n’en ai simplement jamais
entendu
parler.

Ensuite, si je veux trouver une solution, je dirais un truc du genre :

  • créer une classe Behaviour < AR::B pour stocker les comportements
    attribuables / attribués
  • créer une relation habtm entre tes objets et les Behaviours
  • trouver un moyen de lister les modules inclus par tes objets
    métiers
    (c’est peut-être faisable en créant un module parent à tes modules
    qui fasse
    la liaison habtm lors de l’inclusion lors de l’extend)
  • trouver un moyen de faire en sorte que quand tu dépile un de tes
    objets
    (avec un find par exemple) il dépile aussi les Behaviours associés
    réapplique les extend

Perso je trouve que soit tu te complique la vie, soit tu cherche le
mauvais
outil pour résoudre le vrai problème.

Maintenant, si tu veux vraiment chasser cette chimère elle est partie
par lÃ
pointe avec beaucoup de sérieux dans une direction au hasard.

houla, ça me parait bien complexe comme solution. :wink:

les objets n’étant pas définis à l’avance, il faut que tout soit
dynamique.

Oui, c’est assez corsé car le domaine en question nous amène à chaque
fois à pousser à bout tout ce que l’on fait dans le web. Je pense
d’ailleurs revenir très prochainement pour des problèmes de scaling :wink:

Mais je suis sûr une solution assez simple qui me parait pas mal pour le
moment, après avoir décortiqué le code d’Active Record. Je n’ai pas
testé tous les aspects dont j’ai besoin encore, mais ça avance dans le
bon sens, avec les comportements que l’on veut.

Si j’arrive à quelque chose de satisfaisant et facilement explicable,
j’indiquerai ici comment j’ai fait en guise de remerciement pour votre
aide dans ma réflexion.

Charlie Charlie a écrit :

l’application des nouveaux objets avec des comportements différents les
uns des autres, tout ça sans redémarrer l’application ni changer une
ligne de code.
Et une fois ces objets lâcher dans l’application il faut que je puisse
sauvergarder l’état de chacun avec l’état de l’ensemble de leur
composants, tout ça pour pouvoir, quand l’application s’arrête recharger
tous les objets avec leur dernier état connu.

Une solution pourrait être de bien écrire les modèles correspondant aux
objets si l’ensemble des différents types d’objet que peut créer
l’administrateur est un ensemble fini.
Sinon il y a aussi la solution de créer des tables dynamiquement (avec
l’instruction ruby create_table), au fur et à mesure de tes besoins (Ã
chaque fois qu’un type d’objet qui ne correspond à aucune de tes tables
existante est créé), et d’utiliser dr_nick_magic_module pour aller
rapatrier les objets de ces tables créés dynamiquement.

Sinon c’est vrai que tes besoin on l’air assez corsés.