2010-11-12 16 views
16

¿Alguien puede explicar esto?rails seleccionar e incluir

Project.includes([:user, :company]) 

Esto ejecuta 3 consultas, uno a buscar proyectos, uno para ir a buscar a los usuarios de esos proyectos y uno a buscar empresas.

Project.select("name").includes([:user, :company]) 

Esto ejecuta 3 consultas e ignora por completo el bit de selección.

Project.select("user.name").includes([:user, :company]) 

Esto ejecuta 1 consulta con las uniones a la izquierda apropiadas. Y todavía ignora por completo la selección.

Me parece que los rieles ignoran select con includes. Bien, pero ¿por qué cuando pongo un modelo relacionado en seleccionar, ¿se pasa de emitir 3 consultas a emitir 1 consulta?

Tenga en cuenta que la consulta 1 es lo que quiero, simplemente no puedo imaginar que esta es la forma correcta de obtenerla ni por qué funciona, pero no estoy seguro de qué otra manera obtener los resultados en una consulta (. join parece usar INNER JOIN, lo que de hecho no quiero, y cuando especifico manualmente las condiciones de unión para unirme a la gema de búsqueda, estamos utilizando freaks out cuando intenta volver a agregar joins con el mismo nombre).

+0

posible duplicado de [Rieles 3 - seleccionar con Incluir?] (Http://stackoverflow.com/questions/4047833/rails-3-select-with-include) –

Respuesta

8

Allright lo que aquí es lo que me ocurrió ...

.joins("LEFT JOIN companies companies2 ON companies2.id = projects.company_id LEFT JOIN project_types project_types2 ON project_types2.id = projects.project_type_id LEFT JOIN users users2 ON users2.id = projects.user_id") \ 
.select("six, fields, I, want") 

Works, dolor en el trasero, pero me pone simplemente los datos que necesito en una consulta. La única parte mala es que tengo que darle a todo un alias de modelo2 ya que estamos usando meta_search, que parece no ser capaz de darse cuenta de que una tabla ya está unida cuando usted especifica sus propias condiciones de unión.

+0

Sé que es vaga, pero la respuesta correcta es 'No optimizar en exceso'. 99% de las veces solo deja que lo haga. – Kevin

0

Me falta algo aquí pero select y include no forman parte de ActiveRecord. La forma habitual de hacer lo que estamos tratando de hacer es la siguiente:

Project.find(:all, :select => "users.name", :include => [:user, :company], :joins => "LEFT JOIN users on projects.user_id = users.id") 

Tome un vistazo a la api documentation para más ejemplos. De vez en cuando he tenido que ir manual y utilizar find_by_sql:

Project.find_by_sql("select users.name from projects left join users on projects.user_id = users.id") 

Esperamos que esto te orientará en la dirección correcta.

+2

seleccionar e incluir son parte de la interfaz de consulta Rails 3 http://guides.rubyonrails.org/active_record_querying.html – rwilliams

+0

Pensé que podría haber sido el caso (todavía tengo que profundizar en v3), aunque no pude encontrar una referencia a ellos en los documentos de API. La sintaxis parece un poco contra-intuitiva por lo que puedo ver. –

2

Rails siempre ha ignorado el argumento select al usar include o includes. Si desea usar su argumento de selección, entonces use joins.

Puede que tenga un problema con la gema de consulta de la que habla, pero también puede incluir fragmentos sql utilizando el método de uniones.

Project.select("name").joins(['some sql fragement for users', 'left join companies c on c.id = projects.company_id']) 

No conozco su esquema así que tendría que adivinar las relaciones exactas, pero esto debería comenzar.

+1

En realidad, mi pregunta era más similar a la siguiente, si se ignora select, ¿por qué cambia la forma en que se ejecuta la consulta? Específicamente, cuando se utiliza incluye sin seleccionar, hay varias consultas emitidas, una para el modelo de correo y otra para cada asociación. Sin embargo, con select added on, solo se ejecuta una consulta para todos los datos. La razón por la que estoy preguntando esto es por el rendimiento, solo quiero que se ejecute una consulta para estos datos. Y trato de evitar las uniones, ya que usan una combinación interna, o si especifico la combinación izquierda, entonces causan problemas con la gema meta_search cuando intenta agregar la unión de nuevo. – Chad

+0

¿Qué gema de búsqueda estás usando? – rwilliams

+0

meta_search, vea a continuación la solución que tengo por ahora ... – Chad

25

Tuve el mismo problema con select e includes. Para la carga ansiosa de los modelos asociados utilicé la precarga del alcance de los rieles nativos http://apidock.com/rails/ActiveRecord/QueryMethods/preload Proporciona una carga ansiosa sin omitir 'seleccionar' en la cadena de ámbitos.

lo encontré aquí https://github.com/rails/rails/pull/2303#issuecomment-3889821

Esperanza este consejo será útil para alguien como lo fue útil para mí.

+3

Esta es la verdadera respuesta. ': preload' FTW –

0

Yo quería esa funcionalidad, así que úsala. Incluir este método en su clase

#ACCEPTS args en formato de cadena "ASSOCIATION_NAME: COLUMN_NAME-COLUMN_NAME"

def self.includes_with_select(*m) 
    association_arr = [] 
    m.each do |part| 
     parts = part.split(':') 
     association = parts[0].to_sym 
     select_columns = parts[1].split('-') 
     association_macro = (self.reflect_on_association(association).macro) 
     association_arr << association.to_sym 
     class_name = self.reflect_on_association(association).class_name 
     self.send(association_macro, association, -> {select *select_columns}, class_name: "#{class_name.to_sym}") 
    end 
    self.includes(*association_arr) 
    end 

y usted será capaz de llamar como: Contract.includes_with_select ("usuario: id-nombre -status ',' confirmation: confirm-id '), y seleccionará esas columnas especificadas.

Cuestiones relacionadas