web-dev-qa-db-fra.com

ActiveRecord Join Query et sélectionnez dans Rails

Dans mon application Rails 4, un client (table clients) peut avoir plusieurs projets (table projets). J'ai une colonne appelée name dans chaque table. J'essaie d'écrire un join puis select qui utilise des projets comme table de base et des clients comme table de recherche. client_id est le foreign_key dans le tableau des projets:

J'écris ma requête comme suit:

Project.joins(:client).select('projects.id,projects.name,clients.name')

J'obtiens la réponse suivante:

Project Load (0.6ms)  SELECT projects.id,projects.name,clients.name FROM "projects" INNER JOIN "clients" ON "clients"."id" = "projects"."client_id"
=> #<ActiveRecord::Relation [#<Project id: 1, name: "Fantastico Client">]>

Si j'essaie de l'alias comme ça:

Project.joins(:client).select('projects.id,projects.name,clients.name as client_name')

Ensuite, j'obtiens la réponse suivante:

Project Load (0.8ms)  SELECT projects.id,projects.name,clients.name as client_name FROM "projects" INNER JOIN "clients" ON "clients"."id" = "projects"."client_id"
=> #<ActiveRecord::Relation [#<Project id: 1, name: "The Dream Project">]>

Dans les deux cas, ActiveRecord perd l'un des noms comme vous pouvez le voir dans la réponse ci-dessus. Comment dois-je écrire cette requête?

34
Bharat

Si la colonne dans select ne fait pas partie des attributs du modèle sur lequel la select est appelée, ces colonnes ne sont pas affichées. Tous ces attributs sont toujours contenus dans les objets dans AR::Relation et sont accessibles comme tout autre attribut d'instance publique.

Vous pouvez le vérifier en appelant first.client_name:

Project.joins(:client)
       .select('projects.id,projects.name,clients.name as client_name')
       .first.client_name
81
vee

Vous pouvez utiliser :'clients.name' Comme l'un de vos symboles. Par exemple:

Project.select(:id, :name, :'clients.name').joins(:client)

Je l'aime mieux car il semble que Rails le comprend, car il cite tous les paramètres:

SELECT "projects"."id","projects"."name","clients"."name" as "client_name" FROM "projects" INNER JOIN "clients" ON "clients"."id" = "projects"."client_id"

(Je ne suis pas sûr à 100% que c'est la requête SQL exacte, mais je suis assez certain et je le promets va utiliser "clients"."name")

4
Ryan Taylor

votre requête ne perd rien. En fait, vous avez appliqué la jointure sur des modèles et vous avez écrit Project.joins (: client) à quoi cela ressemble. signifie qu'il contiendra les données liées au projet telles quelles et les données associées avec le nom d'alias que vous avez donné 'client_name' dans votre requête.

si tu utilises

Project.joins(:client)
   .select('projects.id project_id, projects.name projects_name,clients.name as client_name')

alors ça ressemble à [#, #]

mais il contient tous les attributs que vous avez sélectionnés.

3
uma