2013-01-22 7 views
9

Ho un'app che ha un numero di modelli Post, ognuno dei quali è il modello User a. Quando questi post vengono pubblicati, viene creato un modello PublishedPost che è il belongs_to relativo al modello Post.ActiveRecord: impossibile utilizzare `pluck` dopo la clausola` where` con associazioni caricate con appetito

Sto cercando di creare una query ActiveRecord per trovare i post pubblicati che corrispondono a un nome utente, quindi ottenere gli ID di quei post pubblicati, ma ricevo un errore quando tento di utilizzare il metodo pluck dopo avido- caricamento delle mie associazioni e ricerca con il metodo where.

Ecco (parte di) il mio controller:

class PublishedPostsController < ApplicationController 

    def index 
    ar_query = PublishedPost.order("published_posts.created_at DESC") 

     if params[:searchQuery].present? 
     search_query = params[:searchQuery] 
     ar_query = ar_query.includes(:post => :user) 
          .where("users.name like ?", "%#{search_query}%") 
     end 

    @found_ids = ar_query.pluck(:id) 

    ... 

    end 

end 

Quando il metodo pluck viene chiamato, ottengo questo:

ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'users.name' in 'where clause': SELECT id FROM `published_posts` WHERE (users.name like '%Andrew%') ORDER BY published_posts.created_at DESC 

posso ottenere i risultati che sto cercando con

@found_ids = ar_query.select(:id).map{|r| r.id} 

ma preferisco usare pluck come sembra il modo più pulito per andare. Non riesco a capire perché non funziona, però. Qualche idea?

risposta

10

È necessario e necessario effettuare joins anziché includes qui.

Le due funzioni sono piuttosto simili, tranne che i dati da joins non vengono restituiti nel risultato della query mentre i dati in un includes sono.

A tale proposito, includes e pluck sono una specie di antitetico. Uno dice di restituirmi tutti i dati che puoi, mentre l'altro dice di darmi solo un po 'di questo.

Poiché si desidera solo una piccola quantità di dati, si desidera eseguire joins. (Stranamente select che sembra anche un po 'in antitesi ancora funziona, ma si sarebbe necessario rimuovere l'ambiguità su id in questo caso.)

Prova ora nella console e vedrete che includes provoca una query che sembra un po' così: SELECT "posts"."id" as t0_ro, "posts"."text" as t0_r1, "users"."id" as t1_r0, "users"."name" as t1_r1 ... Quando metti in virgola su una dichiarazione pluck tutte quelle pazze colonne tx_ry vanno via e vengono sostituite da qualunque cosa tu abbia specificato.

Spero che questo aiuti, ma se non forse questo RailsCast può. È spiegato intorno al marchio dei 5 minuti.

http://railscasts.com/episodes/181-include-vs-joins

9

Se è arrivato qui da ricerca "rotaie cavalo colonna ambiguo", si potrebbe voler sapere che si può semplicemente sostituire query.pluck(:id) con:

query.pluck("table_name.id") 
+0

Yessss! Non so perché questo non è nei documenti? Almeno non l'ho visto. – FireDragon

0

Vostri criteri non avrebbe funzionato come è scritto, anche senza la chiamata di piacere.

Essendo la clausola WHERE la clausola WHERE include SQL letterale che fa riferimento alla tabella degli utenti che Rails non rileva e decide di utilizzare più query e unirsi in memoria (.preload()) invece di unirsi nel livello del database (.eager_load()):

SELECT * from published_posts WHERE users.name like "pattern" ORDER BY published_posts.created_at DESC 
SELECT * from posts WHERE id IN (a_list_of_all_post_ids_in_publised_posts_returned_above) 
SELECT * from users WHERE id IN (a_list_of_all_user_ids_in_posts_returned_above) 

La prima delle 3 query non riesce ed è l'errore che si ottiene.

Per forzare Rails utilizzare un JOIN qui, è necessario utilizzare l'esplicito .eager_load() anziché .includes() o aggiungere una clausola .references().

Oltre a ciò, la risposta di @Geoff è valida, non è necessario .include() qui, ma piuttosto un .joins().

Problemi correlati