2 votes

Ruby on Rails / ActiveRecord : Comment extraire (élégamment) des données de plusieurs tables ?

Il est assez simple d'extraire des données de plusieurs tables liées par des clés étrangères en utilisant le langage SQL brut. Je peux le faire, par exemple :

SELECT title, domestic_sales
FROM movies
  JOIN boxoffice
    ON movies.id = boxoffice.movie_id;

Cela me donnerait un tableau avec deux colonnes : title y domestic_sales où les données de la première colonne proviennent du tableau movies et les données de la deuxième colonne proviennent du tableau boxoffice .

Comment puis-je faire cela dans Rails en utilisant du code Ruby ? Je peux, bien sûr, obtenir le même résultat si j'utilise du SQL brut. Ainsi, je pourrais faire ce qui suit :

ActiveRecord::Base.connection.execute(<<-SQL)
SELECT title, domestic_sales
FROM movies
  JOIN boxoffice
    ON movies.id = boxoffice.movie_id;
SQL

Cela me donnerait un PG::Result avec les données que je veux. Mais c'est super inélégant. J'aimerais pouvoir obtenir ces informations sans utiliser le SQL brut.

Donc, la première chose qui me vient à l'esprit est :

Movie.select(:name, :domestic_sales).joins(:box_office)

Le problème, cependant, c'est que la ligne de code susmentionnée renvoie un groupe de Movie objets. Puisque le Movie ne dispose pas de la classe domestic_sales attribut, je n'ai pas accès à cette information.

La prochaine chose à laquelle j'ai pensé est d'utiliser une boucle. Donc, je pourrais faire quelque chose comme :

Movie.joins(:box_office).to_a.map do |m|
    {name: m.name, rating: m.box_office.domestic_sales}
end

Cela me donne exactement les données que je veux. Mais cela coûte n + 1 requêtes SQL, ce qui n'est pas bon. Je devrais être capable d'obtenir ceci avec une seule requête...

Alors : Comment puis-je récupérer les données que je veux sans utiliser le SQL brut et sans utiliser des boucles qui coûtent plusieurs requêtes ?

1voto

spickermann Points 56572
SELECT title, domestic_sales
FROM movies
  JOIN boxoffice
    ON movies.id = boxoffice.movie_id;

traduit en ActiveRecord ressemblerait à ceci

Movie
  .select(:title, :domestice_sales)
  .joins("boxoffice ON movies.id = boxoffice.movie_id")

Lorsque vous aurez défini les associations appropriées dans vos modèles, vous serez en mesure d'écrire :

Movie
  .select(:title, :domestice_sales)
  .joins(:boxoffices)

Et lorsque vous n'avez pas besoin d'une instance de ActiveRecord et serait bien avec un tableau imbriqué, vous pouvez même écrire :

Movie
  .joins(:boxoffices)
  .pluck(:title, :domestice_sales)

0voto

giri dharan Points 498

Essayez de cette façon.

Movie.joins(:box_office).pluck(:title, :domestic_sales)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X