lundi 3 janvier 2011

Rails 3: Episode 2 => ActiveRelation


L'une des plus grandes et importantes nouveautés de Rails 3 c'est bien ActiveRecord 3.0 qui a été complètement revu (ou ré-écrit). Actuellement ActiveRecord 3.0 est composé de ActiveModel et ActiveRelation ou Arel pour faire court.
L'épisode de cette semaine portera sur ActiveRelation qui est la nouvelle gamme de "Finder" et aussi une implémentation (ruby) de l'algèbre relationnelle.


Le modèle relationnel 


Commençons par une introduction en douceur. C'est quoi le modèle relationnel ? Eh bien, vous avez probablement plus une idée générale de ce que c'est. SQL est une implémentation du modèle relationnel. Je vais pas entrer dans le détails dans cet article.


Le modèle relationnel se compose de deux grands concepts: les relations et les opérateurs. Pour faire court et simple disons que les relations sont similaires aux tables SQL, des vues et des résultats de requête. Les opérateurs sont les différents éléments du langage SQL, tels que SELECT, WHERE et JOIN.


Une des propriétés les plus importantes du modèle relationnel est la propriété de "fermeture". Cela signifie que vous pouvez prendre n'importe quel rapport, effectuer toute opération, et vous en obtiendrez une autre relation. Cela signifie que toute requête peut être utilisée comme une entrée d'une autre requête (qui est juste la notion de sous-requêtes dans SQL).






ActiveRecord 3.0


Alors que ActiveRecord était un outil pour exécuter des requêtes SQL, il est devenu un outil pour construire des relations. La différence est peut être subtile, mais reste importante. L'utilisation du modèle relationnel est l'abstraction correcte, comme nous le verrons tout au long du reste de cet article. Tout d'abord, permettez-moi de souligner quelques changements importants.



@articles = Article.order("created_at DESC")
Dans l'exemple précédent, @articles est une instance de la classe Relation.Cela diffère des versions précédentes de ActiveRecord  @articles aurait été un tableau d'instances de la classe Article.
En outre, il est important de noter que les relations doivent être considérées comme immuables. Une relation est à l'algèbre relationnelle comme un certain nombre(comme 2) est à l'algèbre élémentaire. Il serait un monde fou si 2 pourrait être mutéà représenter un nombre différent.


Le Chaînage

L'apport le plus évident de la nouvelle API est que les opérations peuvent être enchaînées. Cela est dû à la propriété de' fermeture' que j'ai mentionnée plus hautPar exemple, les deux extraits de code suivants sont équivalents.


Article.where(:author => "moi", :category => "inutile")
et

Article.where(:author => "moi").where(:category => "inutile")
Ce n'est pas seulement l'opérateur WHERE qui peut être enchaîné mais tous les autres opérateurs.

Article.where(:author => "moi").order("created_at desc")
 L'objet Relation pourrait même être enregistré dans une variable et utilisé plusieurs fois pour définir des sous-requêtes. Quelque chose comme:



mes_articles = Article.where(:author => "moi")
articles_inutiles = mes_articles.where(:category => "inutile") # vide :)
articles_utiles = mes_articles.where(:category => "utile") 

 Laziness


Les relations sont matérialisées paresseusement. Cela signifie que la requête n'est pas déclenchée avant que les résultats sont réellement utilisés. Cela rend la création de relations quasi-gratuite. Le cas d'utilisation le plus évident est la mise en cache de fragment. Les relations pourrait être construites que la mise en cache soit complète ou partielle.



# controller
def index 
    @articles = Article.where(:author => "hkairi"
end


# la vue

<% cache do %>
   <% @articles.each do |a| %> 
       <h2><%= a.titre %></h2> 
       <%= a.autre_methode %> 
   <% end %> 
<% end %>


Si le fragment est mis en cache,  alors @articles.each ne sera jamais appelé, sauf au moment où la requête devient effectivement utile.Auparavant, le contrôleur aurait enveloppé le bloc (@articles.each) dans une condition pour vérifier si oui ou non le fragment a été déjà mis en cache.



Available finder method 


Les relations ont les méthodes de recherche suivantes à leur disposition:


  • where
  • order
  • limit
  • offset
  • includes
  • joins
  • select
  • having
  • group
  • lock
  • readonly
  • from


  • Sous le capot


    Arel est composé de deux parties principales. La première est le côté formel des choses qui gère les relations et les opérateurs. C'est ce que ActiveRecord utilise dans son API de requêtes. La deuxième composante est l'ensemble des moteurs, qui matérialisent une relation. Cette matérialisation se passe quand une relation est "énuméré" (généralement via un appel à chacun).

    Un moteur est une classe qui répond au CRUD. En d'autres termes, il doit mettre en œuvre les méthodes: créer, lire, mise à jour, et  supprimer,  chaque méthode accepte un seul argument: une instance de relation. Il ya actuellement deux moteurs qui sont construits pour Arel: un moteur SQL et un moteur en mémoire. Le moteur SQL est ce que ActiveRecord utilise.



    Conclusion


    Cela n'a été qu'une brève introduction à la nouvelle API de requête de ActiveRecord. Les caractéristiques actuelles ne sont qu'un début. Le travail se poursuit et Arel sera développé  et son intégration deviendra plus forte.

    2 commentaires:

    1. interessant...donc le find est deprecié pour donner place a where ?

      RépondreSupprimer
    2. Euuuh oui. Surtout pour des soucis de performance. Dans les versions à venir le "find" ne sera plus supporté ! Donc update ...

      RépondreSupprimer