mardi, mars 28, 2006

[Rails] Find by {inserer le nom du champs ici}

Je viens de découvrir un truc génial (encore un):
Ceux qui ont fait des appli qui accèdent à la base de donnée auront surement déjà au besoin d'ajouter des méthodes du genre Adresse.findByCodePostal(codepostal).
Evidement à chaque fois on a jamais celle qui nous faut... avec hibernate le code est relativement simple à écrire. Mais avec Rails c'est encore plus simple! Il n'y a pas besoin de l'écrire!

Imaginons que j'ai une table items avec comme colonne "title", "quantity", "price"...
J'écris directement (dans mon test unitaire par exemple):
  Item.find_by_title('test title')
  Item.find_by_quantity(8)
  Item.find_by_price(123.45)

En fait les find_by_xxx() sont créées à la volée! C'est génial! Il suffit que mon champs existe en base et la méthode correspondante existe toute seule!
Technorati tags:

2 commentaires:

Anonyme a dit…

Perso, ActiveRecord et le MDA de rails sont les arguments de choc qui m'ont fait lorgner du côté de ce framework ^^

Anonyme a dit…

Rails utilise en effet le 'method_missing' de ActiveRecord:Base : si la méthode n'existe pas, on fait tout de même un match d'expression régulière sur
find_by_*(_and_*)
et find_all_by_* (qui doit être deprecated).
Si ça match, on extrait les "argument" de l'expression : si le(s) * sont des champs, on construit la requête.

C'est magique.

Néanmoins, l'utilisation de method_missing montre la limite de ce genre de bidouille, ma fois agréable.

Coté perfs, faut faire un benchmark.
Il est possible de surcharger ActiveRecord:Base avec :
def find_by(match, *conditions)
..
end
et
def find_all_by(match, *conditions)
..
end
qui prennent la premiere chaine comme match, et les suivantes comme conditions.
Par exemple :

@me = Person.find_by name_and_age_and_city 'john' 24 'Paris'

Ne reste plus qu'à traiter le match comme method_missing le fait déjà. Au moins, on passe plus par gestion des exceptions, mais bien par un controle en amont.

--
Un article à ce sujet :
http://blog.hasmanythrough.com/2006/8/13/how-dynamic-finders-work

Le code source : http://dev.rubyonrails.org/browser/trunk/activerecord/lib/active_record/base.rb