2010-11-12 93 views
16

任何人都可以解释这一点吗?导轨选择并包括

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

此执行3个查询,一个获取项目,一个获取用户为这些项目和一个获取公司。

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

这会执行3个查询,并完全忽略选择位。

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

这将执行1个正确的左连接查询。仍然完全忽略了选择。

在我看来,铁轨忽略选择与包括。好吧,但为什么当我把一个相关的模型选择它是否从发出3个查询切换到发出1个查询?

请注意,1查询是我想要的,我无法想象这是正确的方式来获取它,也不知道为什么它的作品,但我不知道如何得到结果在一个查询(。连接似乎只使用INNER JOIN,事实上我并不需要它,而当我手动指定连接条件来连接搜索gem时,我们使用怪物,因为它尝试重新添加具有相同名称的连接)。

+0

可能的重复[Rails 3 - 选择包含?](http://stackoverflow.com/questions/4047833/rails-3-select-with-include) – 2014-01-26 08:58:26

回答

8

还好吧所以这里是我想出了...

.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") 

作品,疼痛的屁股,但它让我只是我需要在一个查询的数据。唯一不好的部分是我必须给所有东西一个model2别名,因为我们使用的是meta_search,这似乎无法确定在指定自己的连接条件时表已经连接了一个表。

+0

我知道它是模糊的,但正确的答案是'不要过度优化'。 99%的时间让它做它的事情。 – Kevin 2012-11-17 21:53:39

0

我可能完全错过了这里的东西,但selectinclude不是ActiveRecord的一部分。通常的方式做你想要做的是这样的:

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

看看在api documentation更多的例子。有时我不得不去手动和使用find_by_sql

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

希望这将指向你在正确的方向。

+2

选择和包含是Rails 3查询接口的一部分http://guides.rubyonrails.org/active_record_querying.html – rwilliams 2010-11-13 00:05:52

+0

我认为可能是这种情况(我还没有深入研究v3),尽管我在API文档中找不到它们的参考。从我所能看到的语法看起来有点反直觉。 – 2010-11-13 05:43:55

2

使用includeincludes时,Rails始终忽略select参数。如果您想使用您的选择参数,请改为使用joins

您可能会遇到查询gem问题,但您也可以使用连接方法包含sql碎片。

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

我不知道你的模式,所以我不得不猜测确切的关系,但这应该让你开始。

+1

其实我的问题更多的是,如果select被忽略,为什么它会改变查询的运行方式?特别是,如果使用includes而不选择,则会发出多个查询,其中包含邮件模型和每个关联一个。但是,如果选择添加,则只会为所有数据运行一个查询。我问这个问题的原因是为了提高性能,我只希望为这些数据执行一个查询。而我试图避免连接,因为它们使用内部连接,或者如果我指定了左连接,那么当它尝试再次添加连接时,它们会导致meta_search gem出现问题。 – Chad 2010-11-15 17:14:41

+0

您正在使用哪个搜索宝石? – rwilliams 2010-11-15 21:26:07

+0

meta_search,请参阅下面的解决方案我现在得到... – Chad 2010-11-20 20:51:52

25

我有选择和包括同样的问题。 对于相关模型的急切加载,我使用了原生Rails作用域'预加载'http://apidock.com/rails/ActiveRecord/QueryMethods/preload 它提供了在范围链中不跳过'select'的紧急加载。

我在这里找到https://github.com/rails/rails/pull/2303#issuecomment-3889821

希望这个提示将是有帮助的人,因为这是对我有帮助。

+3

这是真正的答案。 ':preload' FTW – 2013-06-20 23:13:49

0

我想要自己的功能,所以请使用它。 包括此方法在你的类

字符串格式#ACCEPTS ARGS “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 

你就能像调用:Contract.includes_with_select(“用户:ID名称-status','确认:confirm-id'),并且它将选择那些指定的列。