rails选择并包含

时间:2010-11-12 22:43:07

标签: ruby-on-rails activerecord ruby-on-rails-3

任何人都能解释一下吗?

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

执行3个查询,一个用于获取项目,一个用于获取这些项目的用户,另一个用于获取公司。

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

执行3次查询,完全忽略选择位。

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

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

在我看来,rails忽略select with includes。好的,但是为什么当我在select中放入一个相关的模型时,它会从发出3个查询切换到发出1个查询?

请注意,1查询是我想要的,我无法想象这是获取它的正确方法,也不是它的工作原理,但我不确定如何在一个查询中获得结果(.joins似乎只使用我实际上并不想要的INNER JOIN,当我手动指定连接条件为.joins搜索gem时,我们正在尝试重新添加具有相同名称的连接时使用怪胎。

5 个答案:

答案 0 :(得分:25)

我和select和includes有同样的问题。 为了热切加载相关模型,我使用了原生的Rails范围'preload'http://apidock.com/rails/ActiveRecord/QueryMethods/preload 它提供了急切的负载而没有在范围链上跳过“选择”。

我在https://github.com/rails/rails/pull/2303#issuecomment-3889821

找到了它

希望这个提示对某些人有帮助,因为它对我有帮助。

答案 1 :(得分: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")

工作,屁股上的痛苦,但它只是我在一个查询中需要的数据。唯一糟糕的部分是因为我们正在使用meta_search,所以我必须给出一切model2别名,这似乎无法弄清楚当你指定自己的连接条件时表已经加入了。

答案 2 :(得分:2)

使用selectinclude时,Rails始终忽略includes个参数。如果您想使用您的select参数,请改用joins

您可能遇到了正在讨论的查询gem的问题,但您也可以使用连接方法包含sql片段。

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

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

答案 3 :(得分: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")

希望这会指出你正确的方向。

答案 4 :(得分: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('user:id-name-status','confirmation:confirmed-id'),它将选择那些指定的列。